[ABC347D] Popcount and XOR題解

wuhupai發表於2024-03-31

提供一種好想且與題解截然不同的做法

首先看到異或想到了 01trie,拆位。這是 abc 的 d,且還有兩個條件,01trie 貌似有點大材小用了,所以去想拆位。我們可以按位考慮來滿足異或的條件。考慮怎麼滿足 popcount 的條件。想到 dp,設計 \(dp[i][j][k]\) 為當前做到 \(i\) 位,\(x\) 用了 \(j\)\(1\)\(y\) 用了 \(k\)\(1\) 是否可行,然後轉移方程易得。

\(dp[i][j][k]=dp[i-1][j-1][k-1]|dp[i-1][j][k]\)
\(dp[i][j][k]=dp[i-1][j][k-1]|dp[i-1][j-1][k]\)

第一個轉移方程的意思是如果 \(c\) 這位是 \(0\),那麼 \(x\),\(y\) 這位要麼都是 \(0\),要麼都是\(1\),所以要麼都多用 \(1\) 個,要麼都不用。如果 \(c\) 這位是 \(1\),那麼 \(x\),\(y\) 這位只有一個這位是 \(1\),所以要麼 \(x\) 多用 \(1\) 個,要麼 \(y\) 多用 \(1\) 個。然後題目讓我們輸出構造出來的數,我們只要記錄一下路徑就好了

#include<bits/stdc++.h>
#define for1(i,a,b) for(ll i=(a);i<=(b);i++)
#define for2(i,a,b) for(ll i=(a);i>=(b);i--)
#define mx(a,b) max(a,b)
#define mn(a,b) min(a,b)
#define puba push_back
#define mem(a) memset((a),0,sizeof((a)))
#define ll long long
using namespace std;
struct node{
    ll x,y,z;
}path[65][65][65];
ll a,b,c,dp[65][65][65];
int main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>a>>b>>c;
    dp[0][0][0]=1;
    for1(i,1,60){
        for1(j,0,mn(a,i)){
            for1(k,0,mn(b,i)){
                ll x=(c>>(i-1ll))&1ll;
                if(!x){
                    if(dp[i-1][j][k]){
                        path[i][j][k]={i-1,j,k};
                        dp[i][j][k]=dp[i-1][j][k];
                    }if(j>=1&&k>=1&&dp[i-1][j-1][k-1]){
                        dp[i][j][k]=dp[i-1][j-1][k-1];
                        path[i][j][k]={i-1,j-1,k-1};
                    } 
                }else{
                    if(j>=1&&dp[i-1][j-1][k]){
                        dp[i][j][k]=dp[i-1][j-1][k];
                        path[i][j][k]={i-1,j-1,k};
                    }if(k>=1&&dp[i-1][j][k-1]){
                        path[i][j][k]={i-1,j,k-1};
                        dp[i][j][k]=dp[i-1][j][k-1];
                    }
                }
            }
        }
    }
    if(dp[60][a][b]){
        ll x=60,y=a,z=b,ans1=0,ans2=0;
        while(x){
            if(path[x][y][z].y+1==y) ans1+=(1ll<<(x-1));
            if(path[x][y][z].z+1==z) ans2+=(1ll<<(x-1));//要加1ll,代表這個1是long long否則會炸
            int nx=path[x][y][z].x;
            int ny=path[x][y][z].y;
            int nz=path[x][y][z].z;//注意這裡要臨時存一下,不能現改,否則會影響下面
            x=nx,y=ny,z=nz;
        }
        cout<<ans1<<" "<<ans2<<"\n";
    }else cout<<"-1";
    
    return 0;
}

相關文章