二进制

来源:互联网 发布:淘宝网电动车阳伞 编辑:程序博客网 时间:2024/06/05 11:57

题目

这里写图片描述
这里写图片描述

过程

这是上午考试的第四题。当时自己读完题后,看了数据规模,感觉是故意设计的(本来就是嘛),但是又实在没有方法,就只好打了一个两个dfs嵌套的暴力。。结果(猜也能猜出来):WA×5,TLE×5。
正解:dp。(什么?这破题居然能dp?)
思路:首先预处理出所有的情况,然后O(1)输出。
dp数组开成[32][32][32][32][2]大小,f[l][i][j][k][jin]表示Z的长度最大为l、Xa(2)中1的数量为i、Ya(2)中1的数量为j、Za(2)中1的数量为k、进位为jin的最小的符合条件的答案(没有为-1)。
枚举l、i、j、k、jin以后,如果情况成立,我们用p、q、r分别枚举X、Y、Z的下一位,若情况仍成立,那么我们就可以进行状态转移。状态转移方程如下:

if(f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]==-1||f[l][i][j][k][jin]+r*(1<<l)<f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2])f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]=f[l][i][j][k][jin]+r*(1<<l);

其中,l+1为新生成的Z的长度,i+p、j+q、k+r不必说,(p+q+jin-r)/2为新产生的Z的进位。为什么呢?因为p+q+jin更新了Z,r为新生成的Z的个位,减去r再整除2即为新的Z在二进制下的余数。
其余的请见代码:

#include<cstdio>#include<cstring>#include<iostream>using namespace std;int n,a,b,c,g1,g2,g3,l1,l2,l3,i,len;int f[32][32][32][32][2];void init(int n,int &length,int &ge){    length=ge=0;    while(n)    {        if(n%2) ge++;        n>>=1;        length++;    }}void dp(){    memset(f,-1,sizeof(f));    f[0][0][0][0][0]=0;    for(int l=0;l<=30;l++)      for(int i=0;i<=30;i++)        for(int j=0;j<=30;j++)          for(int k=0;k<=30;k++)            for(int jin=0;jin<=1;jin++)              if(f[l][i][j][k][jin]>=0)                for(int p=0;p<=1;p++)                  for(int q=0;q<=1;q++)                     for(int r=0;r<=1;r++)                      if((p+q+jin)%2==r)                        if(f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]==-1||f[l][i][j][k][jin]+r*(1<<l)<f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2])                          f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]=f[l][i][j][k][jin]+r*(1<<l);}main(){    freopen("binary.in","r",stdin);    freopen("binary.out","w",stdout);    dp();    scanf("%d",&n);    for(i=1;i<=n;i++)    {        scanf("%d%d%d",&a,&b,&c);        init(a,l1,g1);        init(b,l2,g2);        init(c,l3,g3);        len=max(l1,max(l2,l3));        printf("%d\n",f[len][g1][g2][g3][0]);    }}
0 0
原创粉丝点击