3202. 【CQOI2013】二进制a+b

Description

输入三个整数a, b, c,把它们写成无前导0的二进制整数。比如a=7, b=6, c=9,写成二进制为a=111, b=110, c=1001。接下来以位数最多的为基准,其他整数在前面添加前导0,使得a, b, c拥有相同的位数。比如在刚才的例子中,添加完前导0后为a=0111, b=0110, c=1001。最后,把a, b, c的各位进行重排,得到a’, b’, c’,使得a’+b’=c’。比如在刚才的例子中,可以这样重排:a’=0111, b’=0011, c’=1010。

你的任务是让c’最小。如果无解,输出-1。

Solution

考虑 dp。

先统计出 \(a\),\(b\),\(c\) 里 1 的个数,然后统计出最多有多少位 \(n\)。

设 \(f_{i,x,y,z,0/1}\) 表示到了二进制下的第 \(i\) 位,\(a\),\(b\),\(c\) 分别用了 \(x,y,z\) 个 1,上一位是否进位的最小的 \(c'\)。

因为是最小值,所以初值为 \(\inf\)。

转移(我是采用由当前往下个结果转移):

\[f_{i+1,x,y,z,0}=\min(f_{i+1,x,y,z,0},f_{i,x,y,z,0})\\ f_{i+1,x+1,y,z+1,0}=\min(f_{i+1,x+1,y,z+1,0},f_{i,x,y,z,0}+2^i)\\ f_{i+1,x,y+1,z+1,0}=\min(f_{i+1,x,y+1,z+1,0},f_{i,x,y,z,0}+2^i)\\ f_{i+1,x+1,y+1,z+1,1}=\min(f_{i+1,x+1,y+1,z+1,1},f_{i,x,y,z,0}+2^{i+1})\\ f_{i+1,x,y,z,0}=\min(f_{i+1,x,y,z,0},f_{i,x,y,z,1})\\ f_{i+1,x+1,y,z,1}=\min(f_{i+1,x+1,y,z,1},f_{i,x,y,z,1}+2^i)\\ f_{i+1,x,y+1,z,1}=\min(f_{i+1,x,y+1,z,1},f_{i,x,y,z,1}+2^i)\\ f_{i+1,x+1,y+1,z+1,1}=\min(f_{i+1,x+1,y+1,z+1,1},f_{i,x,y,z,1}+2^{i+1}) \]

首先前 4 个转移是没有进位的,第 1 个转移是都不放 1,就直接转移。

第 2、3 个转移是放一个 1,就需要加上 \(2^i\)。

第 4 个转移是放两个 1,此时就会进位,而且是加上 \(2^{i+1}\) 而不是 \(2^i\)。

后面 4 个转移同理,注意下第 5、6 个转移是不需要令 \(z\) 加 1 的,因为只放一个是不影响 \(c\) 中 1 的个数的。

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50
#define inf 0x7f7f7f7f
#define ll long long
using namespace std;
int numa,numb,numc,n;
ll a,b,c,f[N][N][N][N][3];
int lowbit(int x)
{
	int res=0;
	while (x)
	{
		res+=(x&1);
		x>>=1;
	}
	return res;
}
int main()
{
	scanf("%lld%lld%lld",&a,&b,&c);
	n=max((int)log2(a)+1,(int)log2(b)+1);
	n=max(n,(int)log2(c)+1);
	memset(f,inf,sizeof(f));
	numa=lowbit(a);
	numb=lowbit(b);
	numc=lowbit(c);
	f[0][0][0][0][0]=0;
	for (int i=0;i<n;++i)
		for (int x=0;x<=numa;++x)
			for (int y=0;y<=numb;++y)
				for (int z=0;z<=numc;++z)
				{
					ll t=f[i][x][y][z][0];
					f[i+1][x][y][z][0]=min(f[i+1][x][y][z][0],t);
					f[i+1][x+1][y][z+1][0]=min(f[i+1][x+1][y][z+1][0],t+(1<<i));
					f[i+1][x][y+1][z+1][0]=min(f[i+1][x][y+1][z+1][0],t+(1<<i));
					f[i+1][x+1][y+1][z+1][1]=min(f[i+1][x+1][y+1][z+1][1],t+(1<<(i+1)));
					t=f[i][x][y][z][1];
					f[i+1][x][y][z][0]=min(f[i+1][x][y][z][0],t);
					f[i+1][x+1][y][z][1]=min(f[i+1][x+1][y][z][1],t+(1<<i));
					f[i+1][x][y+1][z][1]=min(f[i+1][x][y+1][z][1],t+(1<<i));
					f[i+1][x+1][y+1][z+1][1]=min(f[i+1][x+1][y+1][z+1][1],t+(1<<(i+1)));
				}
	if (f[n][numa][numb][numc][0]>=inf) printf("-1\n");
	else printf("%lld\n",f[n][numa][numb][numc][0]);
	return 0;
}
上一篇:用Floyd算法解决选址问题(附完整matlab代码)


下一篇:全盘免疫Autorun.inf自动播放批处理程序