1. 程式人生 > >BZOJ3107 CQOI2013二進制A+B(動態規劃)

BZOJ3107 CQOI2013二進制A+B(動態規劃)

mes pan main name 一位 tchar for 答案 str

  顯然答案只與a、b、c中各自1的個數及位數有關。a、b只考慮前i位怎麽填時,c最多在第i+1位上為1,而第i+1位及之後的a、b怎麽填都不會對前i位造成影響。於是設f[n][i][j][k][0/1]表示只考慮前n位,a用i個1,b用j個1,c用k個1,且c的第n+1位為0/1時的最小值。轉移時枚舉下一位a和b各自填0還是1即可。註意230是有31位的,防止爆int。本來輸出的時候是三目運算符的結果發現-1會輸出成232-1。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include
<cstring> #include<algorithm> using namespace std; #define N 32 #define int unsigned int #define inf ((1<<31)-1) int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3
)+(c^48),c=getchar(); return x*f; } int a,b,c,n,f[N][N][N][N][2]; inline void update(int &x,int y){x=min(x,y);} signed main() { #ifndef ONLINE_JUDGE freopen("bzoj3107.in","r",stdin); freopen("bzoj3107.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n";
#endif a=read(),b=read(),c=read(); int t=0,cnt=0; while (a) t++,cnt+=a&1,a>>=1; n=max(n,t);a=cnt; t=0,cnt=0; while (b) t++,cnt+=b&1,b>>=1; n=max(n,t);b=cnt; t=0,cnt=0; while (c) t++,cnt+=c&1,c>>=1; n=max(n,t);c=cnt; for (int i=0;i<=n;i++) for (int j=0;j<=a;j++) for (int k=0;k<=b;k++) for (int l=0;l<=c;l++) f[i][j][k][l][0]=f[i][j][k][l][1]=inf; f[0][0][0][0][0]=0; for (int i=0;i<n;i++) for (int j=0;j<=min(a,i);j++) for (int k=0;k<=min(b,i);k++) for (int l=0;l<=min(c,i+1);l++) { update(f[i+1][j][k][l][0],min(f[i][j][k][l][0],f[i][j][k][l][1])); update(f[i+1][j+1][k][l+1][0],f[i][j][k][l][0]+(1<<i)); update(f[i+1][j][k+1][l+1][0],f[i][j][k][l][0]+(1<<i)); update(f[i+1][j+1][k][l][1],f[i][j][k][l][1]+(1<<i)); update(f[i+1][j][k+1][l][1],f[i][j][k][l][1]+(1<<i)); if (i+1<n) update(f[i+1][j+1][k+1][l+1][1],min(f[i][j][k][l][0],f[i][j][k][l][1])+(1<<i+1)); } if (f[n][a][b][c][0]==inf) cout<<-1; else cout<<f[n][a][b][c][0]; return 0; }

BZOJ3107 CQOI2013二進制A+B(動態規劃)