zoukankan      html  css  js  c++  java
  • BZOJ 3107 二进制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)

    Input

    输入仅一行,包含三个整数(a, b, c)

    Output

    输出仅一行,为(c’)的最小值。

    Sample Input

    7 6 9

    Sample Output

    10

    HINT

    (a,b,c le 2^{30})

    自己难得看出来一道高维的(dp)题目:(f[i][j][k][l][m])表示前(i)位二进制数中,(a’)用了(j)个1,(b’)用了(k)(1),合成的(c’)在前(i)位中有(l)(1)
    于是,根据二进制加法,我们可以得到(dp)方程:

    [f[i+1][j+1][k][l+1][0] = min(f[i+1][j+1][k][l+1][0],f[i][j][k][l][0] mid (1 ll i)) ]

    [f[i+1][j+1][k][l][1] = min(f[i+1][j+1][k][l][1],f[i][j][k][l][1]) ]

    [f[i+1][j][k+1][l+1][0] = min(f[i+1][j][k+1][l+1][0],f[i][j][k][l][0] mid (1 ll i)) ]

    [f[i+1][j][k+1][l][1] = min(f[i+1][j][k+1][l][1],f[i][j][k][l][1]) ]

    [f[i+1][j+1][k+1][l][1] = min(f[i+1][j+1][k+1][l][1],f[i][j][k][l][0]) ]

    [f[i+1][j+1][k+1][l+1][1] = min(f[i+1][j+1][k+1][l+1][1],f[i][j][k][l][1] mid (1 ll i)) ]

    [f[i+1][j][k][l+1][0] = min(f[i+1][j][k][l+1][0],f[i][j][k][l][1] mid (1 ll i)) ]

    [f[i+1][j][k][l][0] = min(f[i+1][j][k][l][0],f[i][j][k][l][0]) ]

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    typedef long long ll;
    #define maxn (35)
    ll a,b,c,f[maxn][maxn][maxn][maxn][2];
    int n,w1,w2,w3;
    
    inline void ready()
    {
    	memset(f,0x7,sizeof(f));
    	f[0][0][0][0][0] = 0;
    	int cnt,i;
    	for (i = a,cnt = 0;i;i >>= 1,++cnt) if (i & 1) ++w1;
    	n = max(n,cnt);
    	for (i = b,cnt = 0;i;i >>= 1,++cnt) if (i & 1) ++w2;
    	n = max(n,cnt);
    	for (i = c,cnt = 0;i;i >>= 1,++cnt) if (i & 1) ++w3;
    	n = max(n,cnt);
    }
    
    inline void dp()
    {
    	for (int i = 0;i < n;++i)
    		for (int j = 0;j <= i&&j <= w1;++j)
    			for (int k = 0;k <= i&&k <= w2;++k)
    				for (int l = 0;l <= i&&l <= w3;++l)
    				{
    					if (j < w1)
    					{
    						if (l < w3) f[i+1][j+1][k][l+1][0] = min(f[i+1][j+1][k][l+1][0],f[i][j][k][l][0]|(1<<i));
    						f[i+1][j+1][k][l][1] = min(f[i+1][j+1][k][l][1],f[i][j][k][l][1]);
    					}
    					if (k < w2)
    					{
    						if (l < w3) f[i+1][j][k+1][l+1][0] = min(f[i+1][j][k+1][l+1][0],f[i][j][k][l][0]|(1<<i));
    						f[i+1][j][k+1][l][1] = min(f[i+1][j][k+1][l][1],f[i][j][k][l][1]);
    					}
    					if (j < w1&&k < w2)
    					{
    						f[i+1][j+1][k+1][l][1] = min(f[i+1][j+1][k+1][l][1],f[i][j][k][l][0]);
    						if (l < w3) f[i+1][j+1][k+1][l+1][1] = min(f[i+1][j+1][k+1][l+1][1],f[i][j][k][l][1]|(1<<i));
    					}
    					if (l < w3) f[i+1][j][k][l+1][0] = min(f[i+1][j][k][l+1][0],f[i][j][k][l][1]|(1<<i));
    					f[i+1][j][k][l][0] = min(f[i+1][j][k][l][0],f[i][j][k][l][0]);
    				}
    }
    
    int main()
    {
    	freopen("3107.in","r",stdin);
    	freopen("3107.out","w",stdout);
    	scanf("%lld %lld %lld",&a,&b,&c);
    	ready();
    	dp();
    	if (f[n][w1][w2][w3][0] > (1ll<<40)) printf("-1");
    	else printf("%lld",f[n][w1][w2][w3][0]);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    C# 中的委托和事件
    css样式大全(整理版)
    (转)VS2010 快捷键
    委托小例子
    .NET中Cache的使用
    ObjectiveC面向对象编程继承
    ObjectiveC简介
    ObjectiveC面向对象编程实例化对象、构造函数
    MSSql的多表关联的update语句
    ObjectC 与 Java 区别
  • 原文地址:https://www.cnblogs.com/mmlz/p/4299873.html
Copyright © 2011-2022 走看看