Educational Codeforces Round 66 (Rated for Div. 2)

南楼画角 提交于 2021-02-11 20:35:36

要是有题目FST了就重新写

A

签到

#include<bits/stdc++.h>
using namespace std;
int T;
long long n,k,ans;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>k,ans=0;
        while(n)
        {
            ans+=n%k;
            ans++,n/=k;
        }
        cout<<ans-1<<endl;
    }
}
View Code

B

暴力模拟,记得打标记和开long long,注意特判

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
int T,top;
char str[101];
ll ans,st[N];
int main()
{
    scanf("%d",&T);
    st[0]=1;
    while(T--)
    {
        scanf("%s",str);
        if(str[0]=='a')
        {
            if(st[top]==-1)ans=-1;
            else ans+=st[top];
            if(st[top]==-1||ans>=(1ll<<32)){puts("OVERFLOW!!!");return 0;}
        }
        else if(str[0]=='f')
        {
            ll x;scanf("%I64d",&x);
            if(st[top]==-1)st[top+1]=-1;
            else st[top+1]=x*st[top];
            top++;
            if(st[top]>=(1ll<<32))st[top]=-1;
        }
        else top--;
    }
    cout<<ans;
}
View Code

C

我写个O(nlogn)复杂了,实际上是签到题,我还写个二分

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int n,k,pos,a[N];
bool check(int d)
{
    for(int l=1,r=1;l<=n;l++)
    {
        while(r<n&&a[r+1]-a[l]<=2*d)r++;
        if(r-l+1>k){pos=a[l]+d;return 1;}
    }
    return 0;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int L=0,R=a[n]-a[1],mid,ans=R;
        while(L<=R)
        {
            mid=L+R>>1;
            if(check(mid))ans=mid,R=mid-1;
            else L=mid+1;
        }
        printf("%d\n",pos);
    }
}
View Code

D

发现是k段后缀和,其中[1,n]必须得选,其余[2,n]...[n,n]选最大的k段即可。

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,k,a[N];
long long ans,s[N];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    if(n==1){printf("%d",a[1]);return 0;}
    for(int i=n;i;i--)s[i]=s[i+1]+a[i];
    sort(s+2,s+n+1);
    reverse(s+2,s+n+1);
    for(int i=1;i<=k;i++)ans+=s[i];
    cout<<ans;
}
View Code

E

首先求出每个位置仅用一条线段能走到哪,这个显然可以线段树覆盖(实际上排序也许,不过线段树太好想了)。然后愉快地倍增即可。

#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int N=5e5+7;
int n,m,all=5e5,lazy[N<<2],mx[N<<2],fa[N][20];
void modify(int rt,int v){lazy[rt]=max(lazy[rt],v),mx[rt]=max(mx[rt],v);}
void pushdown(int rt)
{
    if(!lazy[rt])return;
    modify(rt<<1,lazy[rt]),modify(rt<<1|1,lazy[rt]);
    lazy[rt]=0;
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&r<=R){modify(rt,v);return;}
    pushdown(rt);
    int mid=l+r>>1;
    if(L<=mid)update(L,R,v,lson);
    if(R>mid)update(L,R,v,rson);
    mx[rt]=max(mx[rt],mx[rt<<1|1]);
}
void query(int l,int r,int rt)
{
    if(l==r){fa[l][0]=max(l,mx[rt]);return;}
    pushdown(rt);
    int mid=l+r>>1;
    query(lson),query(rson);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=n;i++)scanf("%d%d",&x,&y),update(x,y,y,0,all,1);
    query(0,all,1);
    for(int j=1;j<=19;j++)
    for(int i=0;i<=all;i++)
    fa[i][j]=fa[fa[i][j-1]][j-1];
    while(m--)
    {
        int x,y,ans=0;scanf("%d%d",&x,&y);
        for(int i=19;~i;i--)if(fa[x][i]<y)x=fa[x][i],ans+=(1<<i);
        if(fa[x][0]<y)puts("-1");
        else printf("%d\n",ans+1);
    }
}
View Code

F

我们可以从后向前扫,然后找以i为起点的答案。显然区间内不能有相同的数字,于是可以记录nxt[i]数组表示从i位置向后延展到nxt[i]-1处数字均互不相同,这个显然线性维护。由于区间要求值为[1,len],所以很容易发现越短的区间最大值越小,所以从后向前扫时,仅需维护一个单调递减的队列,然后对于队列中相邻的数,根据位置和该位置的值,建立树状数组即可。复杂度O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,qs,qe,a[N],b[N],c[N],nxt[N],q[N];
long long ans;
void add(int x,int v){if(x>0)while(x<=n)c[x]+=v,x+=x&-x;}
int ask(int x){int ret=0;while(x)ret+=c[x],x-=x&-x;return ret;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    nxt[n+1]=n+1;
    for(int i=1;i<=n;i++)b[i]=n+1;
    for(int i=n;i;i--)
    {
        nxt[i]=min(nxt[i+1],b[a[i]]),b[a[i]]=i;
        while(qs<qe&&a[q[qe-1]]<=a[i])
        {
            if(qs+1<qe)add(q[qe-2]-a[q[qe-1]],-1);
            qe--;
        }
        q[qe++]=i;
        if(qs+1<qe)add(q[qe-2]-a[q[qe-1]],1);
        while(qs<qe&&q[qs]>=nxt[i])
        {
            if(qs+1<qe)add(q[qs]-a[q[qs+1]],-1);
            qs++;
        }
        ans+=ask(n)-ask(i-1);
        if(nxt[i]-a[q[qs]]>=i)ans++;
    }
    cout<<ans;
}
View Code

G

首先显然分层DP,朴素的O(n2k)DP相信考过提高组的人都会,然后考虑如何优化。看着不大的数据范围,想到可能是O(nklogn)这种奇怪的复杂度,然后看着就想到直接分治。分治后,记录从分治点向两边的前缀/后缀最大值,可以跑一遍two-pointer,然后发现每个位置的答案是一次函数,然后就可以写个单调栈就行了。

#include<bits/stdc++.h>
using namespace std;
const int N=20086,inf=0x3f3f3f3f;
struct line{
    int k,b;
    line(){}
    line(int _k,int _b){k=_k,b=_b;}
    int get(int x){return k*x+b;}
}st[N];
int n,k,top,a[N],f[N],g[N],pre[N],suf[N];
bool cmp(line a,line b,line c){return 1ll*(a.k-b.k)*(c.b-a.b)<=1ll*(a.k-c.k)*(b.b-a.b);}
void insert(line x)
{
    while(top&&x.k>=st[top].k)x.b=min(x.b,st[top].b),top--;
    while(top>1&&cmp(st[top-1],st[top],x))top--;
    st[++top]=x;
}
int calc(int x)
{
    if(!top)return inf;
    int l=1,r=top;
    while(l<r)
    {
        int m=l+r>>1;
        if(st[m].get(x)<=st[m+1].get(x))r=m;else l=m+1;
    }
    return st[l].get(x);
}
void solve(int l,int r)
{
    if(l==r)return;
    int m=l+r>>1;
    solve(l,m),solve(m+1,r);
    suf[m+1]=0;for(int i=m;i>=l;i--)suf[i]=max(suf[i+1],a[i]);
    pre[m]=0;for(int i=m+1;i<=r;i++)pre[i]=max(pre[i-1],a[i]);
    top=0;
    for(int i=r,j=l;i>m;i--)
    {
        while(j<=m&&suf[j+1]>=pre[i])if(g[j++]<inf)insert(line(suf[j],g[j-1]-(j-1)*suf[j]));
        f[i]=min(f[i],calc(i));
    }
    top=0;
    for(int i=m+1,j=m;i<=r;i++)
    {
        while(j>=l&&suf[j+1]<=pre[i])if(g[j--]<inf)insert(line(j+1,g[j+1]));
        f[i]=min(f[i],calc(-pre[i])+i*pre[i]);
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=max(pre[i-1],a[i]);
    for(int i=1;i<=n;i++)f[i]=pre[i]*i;
    for(int i=2;i<=k;i++)memcpy(g,f,sizeof g),memset(f,0x3f,sizeof f),solve(1,n);
    printf("%d",f[n]);
}
View Code

result:rank11,rating+=159,精准的没超过rating=2210的小号。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!