zoukankan      html  css  js  c++  java
  • Codeforces Round #664 (Div. 1) 部分简要题解

    自闭了

    A

    所有的(a_i)可以根据是否(leq m)分为两类,枚举使用了多少(leq m)的数,(>m)的数的个数可以直接算出来。

    int n,d,m,m1,m2,a[N],b[N];
    ll s1[N],s2[N];
    
    int main()
    {
        n=read();d=read();m=read();
        rep(i,1,n)
        {
            int x=read();
            if (x>m) a[++m1]=x;
            else b[++m2]=x;
        }
        sort(a+1,a+1+m1);sort(b+1,b+1+m2);
        reverse(a+1,a+1+m1);reverse(b+1,b+1+m2);
        ll ans=0;
        rep(i,1,m1) s1[i]=s1[i-1]+a[i];
        rep(i,1,m2) s2[i]=s2[i-1]+b[i];
        rep(i,0,m2)
        {
            ll now=s2[i];
            int rst=(n-i-1)/(d+1)+1;
            //cout << i << " " << rst << endl;
            now+=s1[min(rst,m1)];
            ans=max(now,ans);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    B

    考虑枚举(k)的全排列判断是否合法,注意到一个合法的(c)序列应满足选出来的边形成了若干个简单环,即所有点的入度和出度均为1。记(cant_{i,j,p,q})表示当(c_i=j,c_p=q)时是否存在某个点的入度或者出度(>1).这个数组可以在保证(c_i=j,c_p=q)均合法时使用bitset加速判断。

    int n,m,k,up,c[10],len[10][10],ans=0;
    vector<pii> edge[10][10],sq[N];
    bool cant[10][10][10][10],ban[10][10];
    bitset<N> in[10][10],out[10][10];
    
    void dfs(int dep,int sum)
    {
        if (dep>k) {ans+=(sum==n);return;}
        rep(i,1,dep)
        {
            if (ban[dep][i]) continue;
            int ok=1;
            rep(j,1,dep-1)
            {
                if (cant[j][c[j]][dep][i]) {ok=0;break;}
            }
            if (!ok) continue;
            c[dep]=i;
            dfs(dep+1,sum+len[dep][i]);
        }
    }
    
    int main()
    {
        n=read();m=read();k=read();
        rep(i,1,m)
        {
            int u=read()-1,v=read()-1,w=read();
            sq[u].pb(mkp(w,v));
        }
        rep(u,0,n-1)
        {
            int d=sq[u].size();
            sort(sq[u].begin(),sq[u].end());
            rep(j,1,d)
            {
                int v=sq[u][j-1].sec,w=sq[u][j-1].fir;
                edge[d][j].pb(mkp(u,v));
            }
        }
        rep(d,1,k) rep(i,1,d) 
        {
            len[d][i]=edge[d][i].size();
            rep(j,0,len[d][i]-1)
            {
                int u=edge[d][i][j].fir,v=edge[d][i][j].sec;
                if ((in[d][i][v]) || (out[d][i][u])) {ban[d][i]=1;break;}
                in[d][i][v]=1;out[d][i][u]=1;
            }
        }
        rep(d1,1,k) rep(i1,1,d1) 
        {
            if (ban[d1][i1]) continue;
            rep(d2,d1+1,k) rep(i2,1,d2)
            {
                if (ban[d2][i2]) continue;
                if (((in[d1][i1]&in[d2][i2]).any()) || ((out[d1][i1]&out[d2][i2]).any())) cant[d1][i1][d2][i2]=1;
            }
        }
        dfs(1,0);
        printf("%d",ans);
        return 0;
    }
    

    C

    两个串相似等价于两个串中B和N的个数是相同的,对某个给定的字符串,用一个二元组((x,y))来刻画其中B和N的个数,注意到(x>0,y>0)时串中一定存在BN或NB,那么((x_1,y_1) o (x_2,y_2))的最少操作次数如下:

    [egin{cases} max(|x_1-x_2|,|y_1-y_2|) & mathrm{sgn}(x1-x2)=mathrm{sgn}(y_1-y_2)\ |x_1-x_2|+|y_1-y_2|& mathrm{sgn}(x1-x2) eq mathrm{sgn}(y_1-y_2) end{cases} ]

    其中(mathrm{sgn}(x))表示x的正负性。

    考虑原问题,一个显然的想法是二分一个最大的操作次数mid再判断是否存在一个满足条件的串。check时首先对每个(x_i,y_i)都有一个变化区间,如果最后(mathrm{sgn}|x'-x|=mathrm{sgn}|y'-y|),那么(x')(y')的差也会有一个区间的限制。对所有同类的区间求交后可以枚举(x‘)的取值,根据y的取值区间和差的取值区间找寻是否有合法的y即可。

    int n,x[N],y[N];
    char s[N];
    
    int chk(int mid)
    {
        int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
        rep(i,1,n)
        {
            xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
            yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
            mnd=max(mnd,y[i]-x[i]-mid);
            mxd=min(mxd,y[i]-x[i]+mid);
        }
        rep(i,xl,xr)
        {
            int l=max(yl,i+mnd),r=min(yr,i+mxd);
            l=max(0,l);
            if ((!i) && (!r)) continue;
            if (l<=r) return 1;
        }
        return 0;
    }
    
    void chk2(int mid)
    {
        int xl=0,xr=1e9,yl=0,yr=1e9,mnd=-1e9,mxd=1e9;
        rep(i,1,n)
        {
            xl=max(xl,x[i]-mid);xr=min(xr,x[i]+mid);
            yl=max(yl,y[i]-mid);yr=min(yr,y[i]+mid);
            mnd=max(mnd,y[i]-x[i]-mid);
            mxd=min(mxd,y[i]-x[i]+mid);
        }
        rep(i,xl,xr)
        {
            int l=max(yl,i+mnd),r=min(yr,i+mxd);
            l=max(0,l);
            if ((!i) && (!r)) continue;
            if (l<=r) 
            {
                rep(j,1,i) putchar('B');
                rep(j,1,r) putchar('N');
                return;
            }
        }
    }
    
    int main()
    {
        n=read();
        rep(i,1,n)
        {
            scanf("%s",s+1);
            int m=strlen(s+1);
            rep(j,1,m)
            {
                if (s[j]=='B') x[i]++;else y[i]++;
            }
        }
        int l=0,r=1e9,ans=0;
        while (l<=r)
        {
            int mid=(l+r)>>1;
            if (chk(mid)) {ans=mid;r=mid-1;}
            else l=mid+1;
        }
        printf("%d
    ",ans);
        chk2(ans);
        return 0;
    }
    

    D

    (f_{u,0/1})表示已处理完子树(u)的所有边,且(u o fa_u)的边是向下/上的最小的t之和。注意到子树的根(u)的贡献只与状态的第二维和它儿子中向上走的个数有关,故在当前状态合法时,可以先强制所有边均是从u向下走的,再枚举有几个儿子为向上走(这一部分的(f_v)的贡献可以由贪心算出),再尽可能的合并路径后算出(t_u)的贡献。

    struct node{int to,nxt;}sq[N<<1];
    int all=0,head[N];
    void addedge(int u,int v)
    {
        all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
    }
    
    int n,h[N],t[N];
    ll f[N][2];
    
    void dfs(int u,int fu)
    {
        vl g;g.clear();ll sum=0;
        go(u,i)
        {
            if (v==fu) continue;
            dfs(v,u);
            sum+=f[v][0];
            g.pb(f[v][1]-f[v][0]);
        }
        sort(g.begin(),g.end());
        int m=g.size();ll tmp=sum;
        if ((!fu) || (h[u]<=h[fu]))
        {
            f[u][0]=tmp+1ll*t[u]*max(m,1);
            rep(i,1,m)
            {
                tmp+=g[i-1];
                f[u][0]=min(f[u][0],tmp+1ll*t[u]*max(m-i,i+(fu>0)));
            }
        }
        else f[u][0]=1e12;
        tmp=sum;
        if ((!fu) || (h[u]>=h[fu]))
        {
            f[u][1]=tmp+1ll*t[u]*(m+(fu>0));
            rep(i,1,m)
            {
                tmp+=g[i-1];
                f[u][1]=min(f[u][1],tmp+1ll*t[u]*max(m-i+(fu>0),i));
            }
        }
        else f[u][1]=1e12;
    }
    
    int main()
    {
        n=read();
        rep(i,1,n) t[i]=read();
        rep(i,1,n) h[i]=read();
        rep(i,1,n-1)
        {
            int u=read(),v=read();
            addedge(u,v);addedge(v,u);
        }
        dfs(1,0);
        printf("%lld",min(f[1][0],f[1][1]));
        return 0;
    }
    
  • 相关阅读:
    dns
    sqlserver中int 类型的字段,值为null的时候引发一个问题
    后台读取数据库中值,返回的值出乎意料,并引发了StackOverflowException
    软件设计原则的一些学习总结
    Python基础(5):模块
    SQL 知识纲要
    Linux编程学习笔记Devices
    Python基础(3):函数
    Python基础(2):控制结构
    Python基础(4):类
  • 原文地址:https://www.cnblogs.com/encodetalker/p/13495771.html
Copyright © 2011-2022 走看看