P4574 [CQOI2013]二进制A+B 题解(数位dp)
题目链接
题目思路
想不到居然是数位dp
\(dp[i][j][k][u][0/1]\)
表示枚举到第\(i\)位,\(a\)用了\(j\)个1,\(b\)用了\(k\)个1,\(c\)用了\(u\)个1,以及最后一位是否进位
这个dp转移有点阴间 要好好理解才能明白其中的细节
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=30+5,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n;
int a,b,c;
int numa,numb,numc;
ll dp[maxn][maxn][maxn][maxn][2];
int get(int x){
int cnt=0;
while(x){
if(x&1) cnt++;
x/=2;
}
return cnt;
}
int main(){
memset(dp,0x3f,sizeof(dp));
cin>>a>>b>>c;
numa=get(a),numb=get(b),numc=get(c);
n=max({(int)log2(a)+1,(int)log2(b)+1,(int)log2(c)+1});
dp[0][0][0][0][0]=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=numa;j++){
for(int k=0;k<=numb;k++){
for(int u=0;u<=numc;u++){
ll add=dp[i][j][k][u][0];
dp[i+1][j+1][k+1][u+1][1]=min(dp[i+1][j+1][k+1][u+1][1],add+(1<<i+1));
dp[i+1][j][k+1][u+1][0]=min(dp[i+1][j][k+1][u+1][0],add+(1<<i));
dp[i+1][j+1][k][u+1][0]=min(dp[i+1][j+1][k][u+1][0],add+(1<<i));
dp[i+1][j][k][u][0]=min(dp[i+1][j][k][u][0],add);
add=dp[i][j][k][u][1];
dp[i+1][j+1][k+1][u+1][1]=min(dp[i+1][j+1][k+1][u+1][1],add+(1<<i+1));
dp[i+1][j][k+1][u][1]=min(dp[i+1][j][k+1][u][1],add+(1<<i));
dp[i+1][j+1][k][u][1]=min(dp[i+1][j+1][k][u][1],add+(1<<i));
dp[i+1][j][k][u][0]=min(dp[i+1][j][k][u][0],add);
}
}
}
}
ll ans=dp[n][numa][numb][numc][0];
if(ans>=INF) ans=-1;
cout<<ans<<'\n';
return 0;
}
不摆烂了,写题