提供一種好想且與題解截然不同的做法
首先看到異或想到了 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;
}