BZOJ3107 [cqoi2013]二进制a+b

题面在这里

\(f_{t,i,j,k,0/1}\)表示\(a\)用了\(i\)个1,\(b\)用了\(j\)个1,\(c\)用了\(k\)个1的最小\(c\)

手动暴力转移即可

示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<cstdio>
#include<cstring>
#define cl(x,y) memset(x,y,sizeof(x))
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=35;
int a,b,c,sa,sb,sc,n,w[maxn];
ll f[maxn][maxn][maxn][maxn][2],INF;
inline void up(ll &a,ll b) {a=min(a,b);}
int main(){
scanf("%d%d%d",&a,&b,&c);
int len=0;
while (a) sa+=a%2,a/=2,len++; n=max(n,len);
len=0;
while (b) sb+=b%2,b/=2,len++; n=max(n,len);
len=0;
while (c) sc+=c%2,c/=2,len++; n=max(n,len);
w[0]=1;
for (int i=1;i<=n;i++) w[i]=w[i-1]<<1;
cl(f,63);INF=f[0][0][0][0][0];
f[0][0][0][0][0]=0;
for (int t=0;t<n;t++)
for (int i=0;i<=sa;i++)
for (int j=0;j<=sb;j++)
for (int k=0;k<=sc;k++){
up(f[t+1][i][j][k][0],f[t][i][j][k][0]);
up(f[t+1][i][j][k+1][0],f[t][i][j][k][1]+w[t]);
up(f[t+1][i+1][j][k+1][0],f[t][i][j][k][0]+w[t]);
up(f[t+1][i][j+1][k+1][0],f[t][i][j][k][0]+w[t]);
up(f[t+1][i+1][j+1][k][1],f[t][i][j][k][0]);
up(f[t+1][i+1][j][k][1],f[t][i][j][k][1]);
up(f[t+1][i][j+1][k][1],f[t][i][j][k][1]);
up(f[t+1][i+1][j+1][k+1][1],f[t][i][j][k][1]+w[t]);
}
if (f[n][sa][sb][sc][0]==INF) puts("-1");
else printf("%lld",f[n][sa][sb][sc][0]);
return 0;
}