zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 66 (Rated for Div. 2)

    要是有题目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
    ",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
    ",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的小号。

  • 相关阅读:
    面向对象-------------------------------面向对象的零散小知识
    面向对象------------------------------反射(面向对象的又一个思路)
    面向对象-------------------------对象和类的属性
    面向对象------------------一些双下方法
    装饰器搞一下
    字符串切片取值规则
    On The Way—Step 2 Python入门之Python内容初始
    socket对于recv函数的理解
    Socket通信原理学习
    [SUCTF 2019]Pythonginx
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10983345.html
Copyright © 2011-2022 走看看