给定三个二进制数a,b,c。对每个数进行重组变为a’,b’,c’。你需要满足a’+b’=c’,并令c’最小。若无解输出-1。
a,b,c<= 231 。
其实,我们发现有用的东西只是a,b,c的最大位数(决定了答案最多可以多少位,注意这里的位数是十进制下的,那么最小的答案都超过极限位数证明输出-1),以及a,b,c中1的个数(记为x,y,z)。为方便讨论,我们应当规定x>=y。
现在我们考虑这样一个子问题。
设为 solve(x,y,z,p) 表示第一个数有x个1,第二个数有y个1,得到的数需要有z个1,其中最低位相加时要加上进位的p=0..1。
很显然了,举个例子x=10,y=5,z=1。
当p=0时:
000001111111111
011110000000001
100000000000000
最优策略是把x个1都堆在后面,最低位放1,然后接下来再放y-1个1,使得c’最高位为1。
所以 solve(x,y,z,0)=2x+y−1
当p=1时:
0000001111111111
0111110000000000
1000000000000000
最优策略是把x个1都堆在后面,但因为有进位,所以最低位不能放1,然后再往前放y个1,同样令c’最高位为1。
所以 solve(x,y,z,1)=2x+y
所以 solve(x,y,z,p)=2x+y−1+p
设x=10,y=5,z=5。
当p=0时:
01111111111
00000011111
10000011110
显然这种情况保证a’,b’最小会最优。因为a’,b’最小时刚好c’有y个1,所以合法。又因为a’,b’最小,所以c’也最小。
所以 solve(x,y,z,0)=2x+2y−2
当p=1时:
001111111111
010000011110
100000011110
这种情况我们只能把b’最低位变成0,然后在第x+1位补上一个1,使得c’的最高位的1落在第x+2位。
所以 solve(x,y,z,1)=2x+1+2y−1−1
所以 solve(x,y,z,p)=2x+p+2y−p−2+p
假设x=10,y=5,z=3。
有点不好搞。我们来看看最低位应该怎么弄,然后可以继续将它分成下一个子问题。先考虑p=0。
如果最低位是1+0=1,那么下一个子问题将会变为 solve(x−1,y,z−1,0) 。
按照策略会继续减,一直到z=1时。
那么答案自然是 2x+y−z∗2z−1+2z−1−1
如果最低位是0+1=1,那么下一个子问题将会变为 solve(x,y−1,z−1,0)
按照策略已知道z=1。
那么答案自然是 2x+y−z∗2z−1+2z−1−1
两种一样,我们合并。
如果最低位是1+1=0,那么下一个子问题将会变为 solve(x−1,y−1,z,0)
按照策略会一直到y=z时。
那么答案自然是 2x−y+z∗2z−1+2z∗2z−1−2∗2z−1
我们进行比较。
第一、二种策略: 2z−1∗(2x+y−z+1)−1
第三种策略: 2z−1∗(2x−y+z+2z−2)
由于我们知道y>z。那么显然第三种策略更优。
p=1可以研究一下,还是1+1最优。
因此可以得知。
solve(x,y,z,p)=2∗solve(x−1,y−1,z−p,1)+p
x=10,y=5,z=8,p=0。
01111111111
00011111000
10011110111
这种情况不需要管进位。
因为初始状态p=0,而这种情况只有初始情况才会出现。
在c’中如果它的1跑的比较后面,它就会比较小。
因此最后z-y位都应该是1+0=1。
直至缩到y=z。
所以 solve(x,y,z,p)=2z−y∗solve(x+y−z,y,y,0)+2z−y−1
x=10,y=5,z=12,p=0。
0111111111100
0111000000011
1110111111111
这种情况同样不需要理进位。
同样我们使c’的1弄到后面去。
因此最后z-x位都应该是0+1=1。
所以 solve(x,y,z,p)=2z−x∗solve(x,y+x−z,x,0)+2z−x−1
不需要理进位。
x=10,y=5,z=15,p=0。
000001111111111
111110000000000
111111111111111
显然可得。
solve(x,y,z,p)=2x+y
solve(x,y,z,p)=-1
最终得到的答案应该和最大位比较。
(写的很优美呢)
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define two(x) (1<<x)
using namespace std;
int i,j,k,l,t,n,m,ans,a,b,c,x,y,z;
int lowbit(int x){
return x&-x;
}
int getone(int x){
int y=0;
while (x){
y++;
x-=lowbit(x);
}
return y;
}
int getws(int x){
int y=0;
while (x){
y++;
x/=2;
}
return y;
}
int solve(int x,int y,int z,int p){
if (z==1) return two(x+y+p-1);
else if (z>1&&z<y) return 2*solve(x-1,y-1,z-p,1)+p;
else if (z==y) return two(x+p)+two(y-p)-2+p;
else if (z>y&&z<=x) return two(z-y)*solve(x+y-z,y,y,0)+two(z-y)-1;
else if (z>x&&z<x+y) return two(z-x)*solve(x,y+x-z,x,0)+two(z-x)-1;
else if (z==x+y) return two(z)-1;
else return -1;
}
int main(){
scanf("%d%d%d",&a,&b,&c);
x=getone(a);y=getone(b);z=getone(c);
n=max(max(getws(a),getws(b)),getws(c));
if (x<y) swap(x,y);
ans=solve(x,y,z,0);
if (getws(ans)>n) ans=-1;
printf("%d\n",ans);
}