Codeforces Round #554 (Div. 2)自闭记

A

签到

#include<bits/stdc++.h>
using namespace std;
int n,m,s[2],t[2],ans;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x;i<=n;i++)scanf("%d",&x),s[x&1]++;
    for(int i=1,x;i<=m;i++)scanf("%d",&x),t[x&1]++;
    ans=min(s[0],t[1])+min(s[1],t[0]);
    printf("%d",ans);
}
View Code

B

要求40次,而log(1e6)≈20,也就是说最多20个二进制位,可以每次翻转最高的“0”位,然后再+1即可。证明:若为11...10...00,则翻转最高0位后直接结束;若为全1,也是直接结束;若后面存在1,翻转后必然存在0,使得最高位向后走。

#include<bits/stdc++.h>
using namespace std;
int n,m,tim,a[1000];
bool judge(int x)
{
    int flag=1;
    for(int i=30;i>=0;i--)
    if(x&(1<<i))flag=0;
    else if(!flag)return 0;
    return 1;
}
int main()
{
    cin>>n;
    while(!judge(n))
    {
        tim++;
        if(tim&1)
        {
            int flag=1;
            for(int i=30;i>=0;i--)if(n&(1<<i))flag=0;else if(!flag){a[++m]=i+1;break;}
            n^=(1<<a[m]+1)-1;
        }
        else n++;
    }
    printf("%d
",tim);
    for(int i=1;i<=m;i++)printf("%d ",a[i]);
}
View Code

C

签到,开始还看成了最大公约数,自闭。其实就是枚举差值的每个因数,暴力加一下即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,d,ans,mn;
void work(ll x)
{
    ll t=(x-a%x)%x,A=a+t,B=b+t,g=A/__gcd(A,B)*B;
    if(g<mn)mn=g,ans=t;
    else if(g==mn&&t<ans)ans=t;
}
int main()
{
    cin>>a>>b;
    if(a==b){cout<<0;return 0;}
    if(a>b)d=a-b;else d=b-a;
    mn=a/__gcd(a,b)*b;
    for(ll i=1;i*i<=d;i++)
    if(d%i==0)work(i),work(d/i);
    cout<<ans;
}
View Code

D

被这题搞自闭了,看到什么最大值对1e9+7取模以为是个神仙题,后来才发现是个SB贪心题,其实就是能选的边尽量选,后来证明了一下:只有一个儿子显然,有两个儿子可以证明:如果自己能选没选,那么两个儿子的边也只能选1个,还会影响后面,如果自己不能选,随机选一个是也是对的。然后可以f[i][j][0/1]表示走了i步,前缀和为j,该点与父亲的边是否被选的节点数有几个,直接暴力转移即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1007,mod=1e9+7;
int n,ans,f[2*N][N][2];
void add(int&x,int y){x=(x+y)%mod;}
int main()
{
    scanf("%d",&n);
    f[1][1][1]=1;
    for(int i=1;i<=2*n;i++)
    for(int j=0;j<=n;j++)
    {
        int lc=n+1,rc=n+1;
        if(j+1<=2*n-i-1)lc=j+1;
        if(j)rc=j-1;
        if(lc>n&&rc>n)continue;
        if(f[i][j][0])
        {
            if(lc<=n&&rc<=n)add(f[i+1][lc][1],f[i][j][0]),add(f[i+1][rc][0],f[i][j][0]);
            else if(lc<=n)add(f[i+1][lc][1],f[i][j][0]);
            else add(f[i+1][rc][1],f[i][j][0]);
        }
        if(f[i][j][1])
        {
            if(lc<=n)add(f[i+1][lc][0],f[i][j][1]);
            if(rc<=n)add(f[i+1][rc][0],f[i][j][1]);
        }
    }
    for(int i=1;i<=2*n;i++)
    for(int j=0;j<=n;j++)
    if(f[i][j][1])add(ans,f[i][j][1]);
    printf("%d",ans);
}
View Code

E

被D搞自闭了,E也不会了。其实这道题有一种很神奇的做法:首先当然把b[i]>c[i]的判掉,然后不难发现相邻2个值中一定一个是最大值,另一个是最小值,然后连接(n-1)条(b[i],c[i])的无向边,然后跑一遍欧拉路,若存在长度为n的欧拉路就可以输出解了。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int n,m,cnt,tot,a[N],b[N],c[N],w[N],hd[N],v[N<<1],nxt[N<<1],vis[N],du[N];
map<int,int>id;
void add(int x,int y)
{
    v[++cnt]=y,nxt[cnt]=hd[x],hd[x]=cnt,du[x]++;
    v[++cnt]=x,nxt[cnt]=hd[y],hd[y]=cnt,du[y]++;
}
int getid(int x)
{
    if(!id[x])w[id[x]=++tot]=x;
    return id[x];
}
void euler(int u)
{
    for(int &i=hd[u];i;i=nxt[i])
    if(!vis[i>>1])vis[i>>1]=1,euler(v[i]);
    a[++m]=u;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)scanf("%d",&b[i]);
    for(int i=1;i<n;i++)scanf("%d",&c[i]);
    cnt=1;
    for(int i=1;i<n;i++)
    if(b[i]>c[i]){puts("-1");return 0;}
    else add(getid(b[i]),getid(c[i]));
    int S=1,num=0;
    for(int i=1;i<=tot;i++)if(du[i]&1)S=i,num++;
    if(num&&num!=2){puts("-1");return 0;}
    euler(S);
    if(m!=n){puts("-1");return 0;}
    for(int i=1;i<=n;i++)printf("%d ",w[a[i]]);
}
View Code

F

神仙题,看某AC代码写了F1,大概是f[i][j][k]表示长为i,走j步,后面覆盖集合为k的方案数,直接根据题意转移状态。后来发现F2也没意思就是一样的做法,加个矩阵快速幂就行了,不过懒得写了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7,mod=1e9+7;
int n,k,m,ans,sz[25],f[N][13][16];
int main()
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<1<<m;i++)sz[i]=sz[i>>1]+(i&1);
    f[1][1][1]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<k;j++)
        for(int S=0;S<1<<m;S++)
        if(f[i][j][S])
        {
            int nS=((S<<1)&((1<<m)-1));
            f[i+1][j][nS]=(f[i+1][j][nS]+f[i][j][S])%mod;
            f[i+1][j+1][nS|1]=(f[i+1][j+1][nS|1]+1ll*f[i][j][S]*(sz[S]+1))%mod;
        }
        int sum=0;
        for(int S=0;S<(1<<m);S++)sum=(sum+f[i][k][S])%mod;
        ans=(ans+1ll*sum*(n-i+1))%mod;
    }
    printf("%d",ans);
}
View Code

新号打的,初始语言默认C差评,被卡了十几分钟CE不知道,十分不爽。

result:rank95 rating+=225 now_rating=1725

原文地址:https://www.cnblogs.com/hfctf0210/p/10766200.html