• cf 1557(div2)


    比赛链接:https://codeforces.com/contest/1557

    一小时做完了A,B,C,剩下一小时想D,也没想出来。不过最终是500多名,上了一百多分,真舒适。因为是和排名有关的计分,所以做题速度很重要啊。

    A

    分析:

    当时感觉是直接让最大数一组,剩下的另一组,写了就过了;

    详细证明 Tutorial 写了。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #define db double
    using namespace std;
    int const N=1e5+5;
    int T,n;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n); db sum=0; int mx=-1e9-1;
            for(int i=1,x;i<=n;i++)
            {
                scanf("%d",&x); sum+=x;
                if(x>mx)mx=x;
            }
            printf("%lf
    ",mx+(sum-mx)/(n-1));
        }
        return 0;
    }
    A

    B

    分析:

    离散化一下,找最多的连续上升子段的个数,小于等于( k )就可以,因为它们内部可以随便再分。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const N=1e5+5;
    int T,n,k,a[N],b[N];
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&k);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
            sort(b+1,b+n+1);
            for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
            int cnt=1;
            for(int i=2;i<=n;i++)
            {
                if(a[i]==a[i-1]+1)continue;
                else cnt++;
            }
            if(cnt<=k)puts("Yes");
            else puts("No");
        }
        return 0;
    }
    B

    C

    分析:

    如果( n )是奇数,那么( & )为( 1 )的位上( igoplus )也是( 1 );所以要枚举( k )个位置上一共有几个( 1 ),分别在哪儿,然后让其他位上都是( 0 )。

    如果( n )是偶数,那么( & )为( 1 )的位上( igoplus )是( 0 );所以枚举哪个位置出现第一个( 1 ),让前面的位都是( 0 ),后面的位随便取;还要加上没有( 1 )的方案数。

    让一个位保证是( 0 ),也就是找到( < n )的偶数个数,让它们在该位取( 1 ),其他数在该位取( 0 )。

    懒得写公式了所以用文字描述了半天;公式看代码即知。

    代码如下:

    #include<iostream>
    #define ll long long
    using namespace std;
    int const N=2e5+5,md=1e9+7;
    int T,n,k;
    ll cc,ans,fc[N],inv[N];
    ll pw(ll x,ll y)
    {
        ll ret=1,a=x%md;
        while(y)
        {
            if(y&1)ret=ret*a%md;
            a=a*a%md;
            y>>=1;
        }
        return ret;
    }
    ll C(int a,int b){return a<b?0:((fc[a]*inv[b])%md*inv[a-b])%md;}
    void init()
    {
        cc=0; ans=0;
        for(int i=0;i<n;i+=2)cc=(cc+C(n,i))%md;
    }
    int main()
    {
        scanf("%d",&T);
        fc[0]=1;
        for(int i=1;i<N;i++)fc[i]=(fc[i-1]*i)%md;
        inv[N-1]=pw(fc[N-1],md-2);
        for(int i=N-2;i>=0;i--)inv[i]=(inv[i+1]*(i+1))%md;
        while(T--)
        {
            scanf("%d%d",&n,&k); init();
            if(k==0){printf("1
    "); continue;}
            if(n%2)
            {
                for(int i=0;i<=k;i++)
                    ans=(ans+C(k,i)*pw(cc,k-i)%md)%md;
            }
            else
            {
                ans=pw(cc,k);
                for(int i=1;i<=k;i++)
                    ans=(ans+pw(cc,k-i)*pw(pw(2,n),i-1)%md)%md;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    C

    D

    分析:

    比赛时想了想线段树、DP,但没有成形的想法。后来做别的去了。

    这题确实是DP,关键是每一行要找到一行来更新它。开一个线段树,每个点存了一个(val)和一个(id),表示在这一点为(1),最大能保留多少行,最后一行是第几行。对于第(i)行,找线段树上它是(1)的所有区间中(val)的最大值,然后把它继承下来,线段树上它所有区间更新成(val=maxleft { val,mx.val+1 ight });若成功更新,对应区间的(id=i)。

    过程中记录(pre[i]),表示更新第(i)行的是哪一行。再记录最大的(val)以及它出现在哪一行。最后就可以找到最大(val)对应的路径,然后输出答案了。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #define mp make_pair
    #define fst first
    #define scd second
    #define pb push_back
    #define ls (u<<1)
    #define rs ((u<<1)|1)
    #define mid ((l+r)>>1)
    using namespace std;
    int const N=6e5+5;
    int n,m,c[N],cnt,pre[N],vis[N];
    struct Nd{
        int val,id;
    }tr[N<<2],lz[N<<2];
    vector<pair<int,int> >qu[N];
    void build(int u,int l,int r)
    {
        if(l==r){tr[u].val=0; tr[u].id=-1; return;}
        build(ls,l,mid); build(rs,mid+1,r);
    }
    Nd bet(Nd a,Nd b){return (a.val>b.val)?a:b;}
    void pup(int u){tr[u]=bet(tr[ls],tr[rs]);}
    void pdn(int u)
    {
        if(lz[u].val==0)return;
        tr[ls]=lz[u]; lz[ls]=lz[u];
        tr[rs]=lz[u]; lz[rs]=lz[u];
        lz[u]=(Nd){0,-1};
    }
    Nd find(int u,int l,int r,int ql,int qr)
    {
        //printf("fd(%d,%d,%d,%d,%d)
    ",u,l,r,ql,qr);
        if(l>r)return (Nd){0,-1};
        if(l>=ql&&r<=qr)return tr[u];
        pdn(u); Nd ret=(Nd){0,-1};
        if(mid>=ql)ret=bet(ret,find(ls,l,mid,ql,qr));
        if(mid<qr)ret=bet(ret,find(rs,mid+1,r,ql,qr));
        return ret;
    }
    void upt(int u,int l,int r,int ql,int qr,Nd s)
    {
        if(l>r)return;
        if(l>=ql&&r<=qr)
        {
            if(tr[u].val<=s.val)tr[u]=s,lz[u]=s;
            else if(l==r)return;
            else
            {
                pdn(u);
                if(tr[ls].val<=s.val)tr[ls]=s,lz[ls]=s;
                else upt(ls,l,mid,ql,qr,s);
                if(tr[rs].val<=s.val)tr[rs]=s,lz[rs]=s;
                else upt(rs,mid+1,r,ql,qr,s);
                pup(u);
            }
            return;
        }
        pdn(u);
        if(mid>=ql)upt(ls,l,mid,ql,qr,s);
        if(mid<qr)upt(rs,mid+1,r,ql,qr,s);
        pup(u);
        return;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,t,l,r;i<=m;i++)
        {
            scanf("%d%d%d",&t,&l,&r);
            qu[t].pb(mp(l,r));
            c[++cnt]=l; c[++cnt]=r;
        }
        sort(c+1,c+cnt+1); cnt=unique(c+1,c+cnt+1)-c-1;
        build(1,1,cnt);
        int ans=0,row=-1;
        memset(pre,-1,sizeof pre);
        for(int i=1;i<=n;i++)
        {
            Nd mx=(Nd){0,-1};
            for(pair<int,int> it:qu[i])
            {
                int ql=lower_bound(c+1,c+cnt+1,it.fst)-c,qr=lower_bound(c+1,c+cnt+1,it.scd)-c;
                mx=bet(mx,find(1,1,cnt,ql,qr));
            }
            //printf("i=%d mx.val=%d mx.id=%d
    ",i,mx.val,mx.id);
            pre[i]=mx.id;
            Nd nw=(Nd){mx.val+1,i};
            if(nw.val>ans)ans=nw.val,row=i;
            for(pair<int,int> it:qu[i])
            {
                int ql=lower_bound(c+1,c+cnt+1,it.fst)-c,qr=lower_bound(c+1,c+cnt+1,it.scd)-c;
                upt(1,1,cnt,ql,qr,nw);
            }
        }
        printf("%d
    ",n-ans);
        while(row>-1)vis[row]=1,row=pre[row];
        for(int i=1;i<=n;i++)
            if(!vis[i])printf("%d ",i);
        return 0;
    }
    D
  • 相关阅读:
    js伪数组转数组
    前端解决跨域几种方式
    mac 下node,yarn安装及版本切换
    如何给一个数组对象去重
    cookie、session、sessionStorage 、localStorage 区别
    moment.js 时间戳转换
    tp框架,addAll方法报错,返回false
    js获得 json对象的个数(长度)
    php 魔术方法和魔术常量
    js 对象的创建方式和对象的区别
  • 原文地址:https://www.cnblogs.com/Zinn/p/15122804.html
Copyright © 2020-2023  润新知