3108: [cqoi2013]图的逆变换
3130: [Sdoi2013]费用流

3107: [cqoi2013]二进制a+b

高橋直樹 posted @ 2013年4月16日 12:05 in BZOJ with tags bzoj CQOI , 1634 阅读

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]);
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter