zoukankan      html  css  js  c++  java
  • 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
    ");
    	else printf("%lld
    ",f[n][numa][numb][numc][0]);
    	return 0;
    }
    
  • 相关阅读:
    百度面试题
    分治法--二分查找、乘方、斐波那契数
    01-11李宁老师学Python视频课程(1):初识Python返回课程
    邮件发送的两种实现方法。
    Docker(一):Docker入门教程
    安装docker及在docker中安装python环境学
    vim编辑器的使用和CentOS有很多不同
    大一编程基础培训]==02-03-04-05课==类型
    大一编程基础培训]==08课==条件判断]==07课==Python的LIST与TUPLE数据类型
    Beautiful Soup 4.2.0 文档¶ BeautifulSoup对象内任何第一个标签入口,使用find()方法。
  • 原文地址:https://www.cnblogs.com/Livingston/p/15374275.html
Copyright © 2011-2022 走看看