zoukankan      html  css  js  c++  java
  • 2021暑期cf加训2

    比赛链接:https://codeforces.com/group/2g1PZcsgml/contest/338475

    A,B,C,F,H,I,J,K;12;今天貌似比之前好了一点。

    A

    分析:

    最长上升子序列。

    代码如下:

    #include<iostream>
    #include<cstring>
    using namespace std;
    int f[55][30];
    char s[55];
    int main()
    {
        scanf("%s",&s); int n=strlen(s);
        f[0][s[0]-'a']=1;
        for(int i=1;i<n;i++)
        {
            int c=s[i]-'a'; f[i][c]=1;//
            for(int j=0;j<26;j++)f[i][j]=max(f[i][j],f[i-1][j]);
            for(int j=0;j<c;j++)f[i][c]=max(f[i][c],f[i-1][j]+1);
            //printf("f[%d][%d]=%d
    ",i,c,f[i][c]);
        }
        int mx=0;
        for(int k=0;k<26;k++)mx=max(mx,f[n-1][k]);
        printf("%d
    ",26-mx);
        return 0;
    }
    me

    B

    分析:

    BFS。

    代码如下:

    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    int const N=55;
    int n,m,len,dx[4],dy[4],stx,sty,edx,edy,ans,vis[N][N][N];
    char s[N][N],op[N];
    struct Nd{
        int x,y,p,cnt;
        bool operator < (const Nd &a) const
        {return cnt>a.cnt;}
    };
    priority_queue<Nd>q;
    void init()
    {
        dx[0]=0; dy[0]=-1; dx[1]=1; dy[1]=0; dx[2]=0; dy[2]=1; dx[3]=-1; dy[3]=0;
        for(int i=0;i<=n;i++)
            for(int j=0;j<m;j++)
            {
                if(s[i][j]=='R')stx=i,sty=j;
                if(s[i][j]=='E')edx=i,edy=j;
            }
    }
    bool can(int x,int y){if(x<0||x>=n||y<0||y>=m)return 0; return s[x][y]!='#';}//=='.'走不到'E'!
    int chg(char c){if(c=='L')return 0; if(c=='D')return 1; if(c=='R')return 2; if(c=='U')return 3;}
    void bfs()
    {
        memset(vis,0x3f3f3f3f,sizeof vis);
        q.push((Nd){stx,sty,0,0});
        int nx,ny;
        while(q.size())
        {
            Nd t=q.top(); q.pop();
            if(t.x==edx&&t.y==edy){ans=t.cnt; break;}
            if(vis[t.x][t.y][t.p]<=t.cnt)continue;
            vis[t.x][t.y][t.p]=t.cnt;
            //printf("x=%d y=%d p=%d cnt=%d vis=%d
    ",t.x,t.y,t.p,t.cnt,vis[t.x][t.y][t.p]);
            //bool fl=0;
            //if(t.x==0&&t.y==1&&t.p==2)fl=1,printf("!cnt=%d
    ",t.cnt);
            for(int i=0;i<=3;i++){
                if(can((nx=t.x+dx[i]),(ny=t.y+dy[i]))&&vis[nx][ny][t.p]>t.cnt+1)
                    q.push((Nd){nx,ny,t.p,t.cnt+1});
                //if(fl)printf("can(%d,%d)=%d vis=%d t.cnt+1=%d
    ",nx,ny,can(nx,ny),vis[nx,ny,t.p],t.cnt+1);
            }
            //fl=0;
            if(t.p>=len)continue;
            q.push((Nd){t.x,t.y,t.p+1,t.cnt+1});
            int dr=chg(op[t.p]);
            //if(t.x==1&&t.y==2&&t.p==3)fl=1,printf("!!cnt=%d
    ",t.cnt);
            if(can((nx=t.x+dx[dr]),(ny=t.y+dy[dr]))){
                    q.push((Nd){nx,ny,t.p+1,t.cnt});
                    //if(fl)printf("nx=%d ny=%d
    ",nx,ny);
            }
            else q.push((Nd){t.x,t.y,t.p+1,t.cnt});
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%s",&s[i]);
        scanf("%s",&op); len=strlen(op);
        init(); bfs();
        printf("%d
    ",ans);
        return 0;
    }
    me

    C

    分析:

    过一遍即可。

    代码如下:

    #include<iostream>
    using namespace std;
    int const N=1e5+5;
    int n,k,len,a[N],ans;
    int main()
    {
        scanf("%d%d%d",&n,&k,&len);
        for(int i=1,p;i<=k;i++)
            scanf("%d",&p),a[p]=1;
        int num=0,l=1,r=len;
        for(int i=1;i<=len;i++)num+=a[i];
        for(;r<=n;r++)
        {
            if(num==0)a[r]=1,a[r-1]=1,ans+=2,num=2;
            else if(num==1)
            {
                if(a[r])a[r-1]=1; else a[r]=1;
                ans++; num=2;
            }
            num-=a[l]; num+=a[r+1];
            l++;
        }
        printf("%d
    ",ans);
        return 0;
    }
    me

    H

    分析:

    直接按右端点排序,DP。

    注意离散化不要写错了!

    代码如下:

    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int const N=4e5+5;
    int n,cnt;
    ll R,tmp[N],f[N];
    struct Nd{
        ll l,r;
    }a[N];
    bool cmp(Nd a,Nd b){return a.r<b.r;}
    int main()
    {
        scanf("%lld%d",&R,&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&a[i].l,&a[i].r);
            tmp[++cnt]=a[i].l; tmp[++cnt]=a[i].r;
        }
        sort(a+1,a+n+1,cmp);
        sort(tmp+1,tmp+cnt+1); cnt=unique(tmp+1,tmp+cnt+1)-tmp-1;///-1!!!
        for(int i=1;i<=n;i++)
            a[i].l=lower_bound(tmp+1,tmp+cnt+1,a[i].l)-tmp,
            a[i].r=lower_bound(tmp+1,tmp+cnt+1,a[i].r)-tmp;
        int p=1;
        for(int i=1;i<=cnt;i++)
        {
            f[i]=f[i-1];
            while(p<=n&&a[p].r<=i)f[i]=max(f[i],f[a[p].l-1]-tmp[a[p].l]+tmp[a[p].r]+1),p++;
            //printf("i=%d tmp=%lld f=%lld
    ",i,tmp[i],f[i]);
        }
        printf("%lld
    ",R-f[cnt]);
        return 0;
    }
    me

    I

    分析:

    贪心先放远处。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int const N=1005;
    int n,k,ca,cb;
    ll ans;
    struct Nd{
        int x,m;
    }a[N],b[N];
    int ab(int x){return (x>0)?x:-x;}
    bool cmp(Nd aa,Nd bb){return ab(aa.x)<ab(bb.x);}
    void work1()
    {
        for(int i=ca;i;i--)
        {
            if(a[i].m==0)continue;
            if(a[i].m>=k)ans+=(ll)a[i].x*(a[i].m/k)*2,a[i].m%=k;
            if(a[i].m==0)continue;
            ans+=(ll)a[i].x*2;
            int res=k-a[i].m,p=i-1; a[i].m=0;
            while(p&&res)
            {
                if(res>a[p].m)res-=a[p].m,a[p].m=0,p--;
                else a[p].m-=res,res=0;
            }
        }
    }
    void work2()
    {
        for(int i=cb;i;i--)
        {
            if(b[i].m==0)continue;
            if(b[i].m>=k)ans+=(ll)(-b[i].x)*(b[i].m/k)*2,b[i].m%=k;
            if(b[i].m==0)continue;
            ans+=(ll)(-b[i].x)*2;
            //printf("a[%d].x=%d m=%d ans=%lld
    ",i,a[i].x,a[i].m,ans);
            int res=k-b[i].m,p=i-1; b[i].m=0;
            while(p&&res)
            {
                if(res>b[p].m)res-=b[p].m,b[p].m=0,p--;
                else b[p].m-=res,res=0;
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1,xx,mm;i<=n;i++)
        {
            scanf("%d%d",&xx,&mm);
            if(xx>=0)a[++ca].x=xx,a[ca].m=mm;
            else b[++cb].x=xx,b[cb].m=mm;
        }
        sort(a+1,a+ca+1,cmp); sort(b+1,b+cb+1,cmp);
        work1(); work2();
        printf("%lld
    ",ans);
        return 0;
    }
    /*
    4 10
    -7 5
    -2 3
    5 7
    9 5
    *//*
    7 1
    9400000 10000000
    9500000 10000000
    9600000 10000000
    9700000 10000000
    9800000 10000000
    9900000 10000000
    10000000 10000000
    */
    me

    J

    分析:

    一个数( v )最多会被( mod log(v) )次,所以问题是怎么快速找到下一个比它小的数;

    可以用线段树或ST表做,都是( log(n) )的。

    代码如下:

    #include<iostream>
    #define ll long long
    #define mid ((l+r)>>1)
    #define ls (u<<1)
    #define rs ((u<<1)|1)
    using namespace std;
    int const N=2e5+5;
    int n,q,tr[N<<2];
    ll a[N],v;
    void upt(int u)
    {
        if(a[tr[ls]]<=a[tr[rs]])tr[u]=tr[ls];
        else tr[u]=tr[rs];
    }
    void build(int u,int l,int r)
    {
        if(l==r){tr[u]=l; return;}
        build(ls,l,mid); build(rs,mid+1,r);
        upt(u);
    }
    ll qry(int u,int l,int r,int ql,int qr)
    {
        ll ret=0;
        if(l==r)return a[l]<=v?l:0;
        if(l>=ql&&r<=qr)
        {
            if(a[tr[ls]]<=v)return qry(ls,l,mid,ql,qr);
            else if(a[tr[rs]]<=v)return qry(rs,mid+1,r,ql,qr);
            else return 0;
        }
        if(mid>=ql)ret=qry(ls,l,mid,ql,qr);
        if(ret)return ret;
        if(mid<qr)ret=qry(rs,mid+1,r,ql,qr);
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,1,n);
        for(int i=1,ql,qr;i<=q;i++)
        {
            scanf("%lld%d%d",&v,&ql,&qr);
            while(ql<=qr)
            {
                int ps=qry(1,1,n,ql,qr); if(!ps)break;
                v%=a[ps]; ql=ps+1;
                //printf("ps=%d
    ",ps);
            }
            printf("%lld
    ",v);
        }
        return 0;
    }
    me

    K

    分析:

    ( f[i] ) 表示至少赢 ( i ) 次的方案数;

    ( f[i] = C_{2^k-r}^{2^i-1} / C_{2^k-1}^{2^i-1} );

    直接( k*2^r )做会TLE,但是复杂度应该是( 2*10^7 )才对,不知为什么;

    所以需要利用上一次的答案,每次转移( O(2^{i-1}) ),就能过了。

    代码如下:

    #include<iostream>
    #include<cmath>
    #define db double
    using namespace std;
    int const N=(1<<20)+5;
    db const eps=1e-6;
    int k,r;
    db f[25],ans;
    int main()
    {
        scanf("%d%d",&k,&r); f[0]=1;
        for(int i=1;i<=k;i++)
        {
            if((1<<i)-1>(1<<k)-r)break;
            //f[i]=1; int L=(1<<k)-(1<<i)-r+2,L2=(1<<k)-r+1,R=(1<<k)-(1<<i),R2=(1<<k)-1;
            //for(int j=L,j2=L2;j<=R;j++,j2++)f[i]*=j,f[i]/=j2;
            f[i]=f[i-1]; int A=(1<<k)-r-(1<<i)+1,B=(1<<k)-(1<<i);
            for(int j=1;j<=(1<<(i-1));j++)f[i]*=(A+j),f[i]/=(B+j);
        }
        for(int i=1;i<=k;i++)ans+=(f[i]-f[i+1])*i;
        printf("%.5lf
    ",ans);
        return 0;
    }
    me
  • 相关阅读:
    Python 中的 __str__ 与 __repr__ 到底有什么差别
    02 LeetCode---链表相加
    01 LeetCode---两数之和
    python 数据结构一 之 线性表
    来自C++的"Const式"傲娇
    string 与 char 字符串区别-1
    超级有爱的并查集入门
    多项式求解
    竞码编程-蓝桥杯模拟赛4-D题
    树的直径-蓝桥杯大臣的旅费
  • 原文地址:https://www.cnblogs.com/Zinn/p/15077204.html
Copyright © 2011-2022 走看看