Tk的排列间异或
题目链接:https://ac.nowcoder.com/acm/contest/107500/F
题意:
给定一个排列,构造一个排列使得 (ai^bi)_sum(1~n) 最大
思路:
有点神秘的这题,本来想着大的数和小的数匹配,结果并不正确
题目要求生成排列,其实就是构建 1~n范围的 每个数字的 映射(map)
所以直接将题目排列按照1,2,3,...n讨论
先打表找规律:找到n为8的排列的映射
1: 000001
2: 000010
3: 000011
·························
4: 000100
5: 000101
6: 000110
··························
7: 000111
8: 001000
发现8和7匹配,6和1匹配,5和2匹配,3和4匹配,最优
(两数按位异或要大,那么每位尽量都要不同)
再看看n为14的排列
1: 000001
2: 000010
3: 000011
4: 000100
5: 000101
6: 000110
7: 000111
....................................
8: 001000
9: 001001
10: 001010
11: 001011
12: 001100
13: 001101
14: 001110
发现14和1,13和2,12和3,11和4,10和5,9和6,8和7匹配,都能让每个数字每一位的1不浪费而最优
因此发现规律:
从n开始往前找
最大位(1的数位)相同的数字构成一块,记为X块。要在 这一整块前面 选出数量与这一块相同的数字来匹配,记为Y块
至于匹配的顺序,则是X块最大的数字与Y块最小的数字进行匹配,然后是X块第二大的与Y块第二小的进行匹配
void solve(){
int n;cin>>n;
map<int,int>mp;
int bit=-1;
int last;
int len;
for(int i=n;i>=1;i--){
for(int j=31;j>=0;j--)
{
if((1ll<<j)&i){
if(bit==-1){
bit=j;
last=i;
break;
}else{
if(j!=bit){
len=(last-i);
for(int p=last;p>i;p--){
mp[p]=(p-2*len+1-2*(p-last));
mp[p-2*len+1-2*(p-last)]=p;
}
i=last-2*len+1;
bit=j;
last=i-1;
break;
}else{
break;
}
}
}
}
}
rep(i,1,n){
int x;cin>>x;
cout<<mp[x]<<' ';
}
}

浙公网安备 33010602011771号