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;
}

posted @ 2021-07-16 15:29  hunxuewangzi  阅读(42)  评论(0编辑  收藏  举报