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]<<' ';
    }
}
posted @ 2025-04-21 17:28  Marinaco  阅读(30)  评论(0)    收藏  举报
//雪花飘落效果