3107: [cqoi2013]二进制a+b
http://www.lydsy.com/JudgeOnline/problem.php?id=3107
| RunID | User | Problem | Result | Memory | Time | Language | Code_Length | Submit_Time |
| 391549 | Liu_Ts | 3107 | Accepted | 1272 kb | 64 ms | C++/Edit | 1466 B | 2013-04-16 11:59:41 |
题意
给三个数a,b,c。
构造三个新二进制数A,B,C,要求每个数与原数中1的个数相同,且满足A+B=C。
求满足条件的最小的C
题解
DP,f[t][i][j][k][p],表示枚举到第t位,A已放i个1,B已放j个1,C已放k个1,若p=0,表示该状态无进位;否则表示有进位。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<climits>
using namespace std;
const int N=31;
int n,a,b,c,f[2][N][N][N][2];
inline int get(int x)
{
int s;
for(s=0;x;x>>=1)
if(x&1) s++;
return s;
}
void init()
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
a=get(x);b=get(y);c=get(z);
x=max(x,max(y,z));
for(n=0;x;x>>=1) n++;
}
void work(int &a,int b)
{
if(a==-1) a=b;
else a=min(a,b);
}
int main()
{
init();
memset(f,-1,sizeof(f));
f[0][0][0][0][0]=0;
int cur=0;
for(int t=0;t<n;t++,cur^=1)
for(int i=0;i<=min(t,a);i++)
for(int j=0;j<=min(t,b);j++)
for(int k=0;k<=min(t,c);k++)
{
if(f[cur][i][j][k][0]!=-1)
{
int now=f[cur][i][j][k][0];
work(f[cur^1][i][j][k][0],now);
if(i+1<=a&&k+1<=c) work(f[cur^1][i+1][j][k+1][0],now+(1<<t));
if(i+1<=a&&j+1<=b) work(f[cur^1][i+1][j+1][k][1],now);
if(j+1<=b&&k+1<=c) work(f[cur^1][i][j+1][k+1][0],now+(1<<t));
}
if(f[cur][i][j][k][1]!=-1)
{
int now=f[cur][i][j][k][1];
work(f[cur^1][i][j][k+1][0],now+(1<<t));
if(i+1<=a) work(f[cur^1][i+1][j][k][1],now);
if(j+1<=b) work(f[cur^1][i][j+1][k][1],now);
if(i+1<=a&&j+1<=b&&k+1<=c) work(f[cur^1][i+1][j+1][k+1][1],now+(1<<t));
}
}
printf("%d\n",f[cur][a][b][c][0]);
}
评论 (0)