题解:P12402 [COI 2025] 贪腐 / Korupcija
神秘构造题。
观察样例思考容易得到当
考虑如何构造方案。
我们尝试将大小为
显然将
注意,我们在做大小为
假设
现在我们完成了回溯要做的事,那么还剩下递归的时候如何把
显然,如果不够分就完蛋了。但由于位运算,每一位其实是独立的,所以我们可以找一个最大的
这个时候,
所以很简单,在
code:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;
int id[25];
bool flag[70],ok;
set<p> s,tmps;
void dfs(int n,int k,vector<int> a){
if(k==(1<<n)){
ok=1;
return;
}
if(flag[k]){
dfs(n,k+1,a);
return;
}
for(int j=0;j<n;j++){
if(a[j]&&!flag[k^(1<<j)]){
a[j]--;
flag[k]=flag[k^(1<<j)]=1;
s.insert({k,k^(1<<j)});
dfs(n,k+1,a);
if(ok) return;
a[j]++;
flag[k]=flag[k^(1<<j)]=0;
s.erase({k,k^(1<<j)});
}
}
}
void work(int n,vector<int> a){
if(n<=6){
dfs(n,0,a);
return;
}
int mx=0,mxid;
for(int i=0;i<n;i++){
if(a[i]>=mx){
mx=a[i];
mxid=i;
}
}
swap(a[mxid],a[n-1]);
int tmpf[25]={0};
for(int i=0;i<n-1;i++){
if((a[i]>>1)&1){
tmpf[i]=1;
a[i]+=2;
a[n-1]-=2;
}
}
a[n-2]+=a[n-1];
tmpf[n-2]+=a[n-1]>>1;
for(int i=0;i<n-1;i++){
a[i]>>=1;
}
work(n-1,a);
for(auto it=s.begin();it!=s.end();){
int x=it->first,y=it->second;
int w=__lg(x^y);
if(tmpf[w]){
tmpf[w]--;
it=s.erase(it);
s.insert({x,x^(1<<n-1)});
s.insert({y,y^(1<<n-1)});
}
else{
if(x<(1<<n-1)&&(y<(1<<n-1))){
s.insert({x^(1<<n-1),y^(1<<n-1)});
}
it++;
}
}
tmps.clear();
for(auto it=s.begin();it!=s.end();it++){
int x=it->first,y=it->second;
x=x^(x&(1<<n-1))^(x&(1<<mxid))^((x>>n-1&1)<<mxid)^((x>>mxid&1)<<n-1);
y=y^(y&(1<<n-1))^(y&(1<<mxid))^((y>>n-1&1)<<mxid)^((y>>mxid&1)<<n-1);
tmps.insert({x,y});
}
s=tmps;
}
int main(){
int n;
vector<int> a;
cin>>n;
if(n==1){
puts("0 1");
return 0;
}
a.resize(n+1);
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]&1){
cout<<-1;
return 0;
}
}
work(n,a);
for(auto x:s){
printf("%d %d\n",x.first,x.second);
}
return 0;
}