BZOJ3107: [cqoi2013]二进制a+b

来源:互联网 发布:usb数据传输线 编辑:程序博客网 时间:2024/06/06 08:54

可以把问题转换成在202n里选a个数,再在里面选b个数,使他们的和在二进制下有c位且最高位不大于2n,使这个和最小
然后可以DP,从20开始选,f[i][j][l][k][0]表示选了前i位,a个数里面选了j个,b个数里面选了l个,和有k位,无进位,最后一位是1就代表有进位,然后DP一下就行了

后记:这题原来可以构造的,Orz PoPoQQQ


code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>using namespace std;const int maxn = 35;int f[maxn][maxn][maxn][maxn][2];int n,a,b,c;int an,bn,cn;void up(int &x,int y){if(y>x)x=y;}void down(int &x,int y){if(y<x)x=y;}int main(){    an=bn=cn=0;    scanf("%d%d%d",&a,&b,&c);    int tmp=0; n=0;    while(a)    {        if(a&1)an++;    a>>=1;        tmp++;    } up(n,tmp); tmp=0;    while(b)    {        if(b&1)bn++;    b>>=1;        tmp++;    } up(n,tmp); tmp=0;    while(c)    {        if(c&1)cn++;    c>>=1;        tmp++;    } up(n,tmp); tmp=0;    for(int i=0;i<=n;i++)        for(int j=0;j<=n;j++)            for(int l=0;l<=n;l++)                for(int k=0;k<=n;k++)                    f[i][j][l][k][0]=f[i][j][l][k][1]=INT_MAX;    for(int i=0;i<=min(an,1);i++)    {        for(int j=0;j<=min(bn,1);j++)        {            f[0][i][j][i^j][i&j]=i+j;            //printf("0 %d %d %d %d %d\n",i,j,i^j,i&j,i+j);        }    }    for(int i=1;i<n;i++)    {        int ap=min(i,an),bp=min(i,bn);        for(int j=0;j<=ap;j++)            for(int l=0;l<=bp;l++)            {                for(int k=0;k<=cn;k++)                {                if(f[i-1][j][l][k][0]!=INT_MAX)                {                    int temp=f[i-1][j][l][k][0];                    // 0 0                    down(f[i][j][l][k][0],temp);                    // 0 1                    if(l<bn)                        down(f[i][j][l+1][k+1][0],temp+(1<<i));                    // 1 0                    if(j<an)                        down(f[i][j+1][l][k+1][0],temp+(1<<i));                    // 1 1                    if(j<an&&l<bn)                        down(f[i][j+1][l+1][k][1],temp+(1<<i+1));                }                if(f[i-1][j][l][k][1]!=INT_MAX)                {                    int temp=f[i-1][j][l][k][1];                    //0 0                    down(f[i][j][l][k+1][0],temp);                    //0 1                    if(l<bn)                    down(f[i][j][l+1][k][1],temp+(1<<i));                    //1 0                    if(j<an)                    down(f[i][j+1][l][k][1],temp+(1<<i));                    //1 1                    if(j<an&&l<bn)                    down(f[i][j+1][l+1][k+1][1],temp+(1<<i+1));                }            //printf("%d %d %d %d %d %d\n",i,j,l,k,0,f[i][j][l][k][0]);            //printf("%d %d %d %d %d %d\n",i,j,l,k,1,f[i][j][l][k][1]);                }            }    }    int ret=f[n-1][an][bn][cn][0];    if(ret==INT_MAX) printf("-1\n");    else printf("%d\n",ret);    return 0;}
0 0
原创粉丝点击