洛谷 P6599 「EZEC-2」异或

题目描述
有 T 组询问,每次给定两个正整数 n,l,

你需要构造一个长度为 l 的正整数序列 a(编号从 1 至 l),且满足 ∀i∈[1,l],都有  ai​∈[1,n]。

求:

i=1∑l ​j=1∑i−1​ai​⊕aj​的最大值。

为了避免答案过大,对于每组询问,只需要输出这个最大值对 10^9+7 取模的结果。

输入格式
第一行一个整数 T,表示数据组数。

接下来第 2 行到第 T+1 行,每行两个整数 n,l ,分别代表 a_i​ 的最大取值与 a 的长度。

输出格式
共 T 行,每行一个整数,对应每组询问的答案对 10^9+7 取模的结果。

输入输出样例
输入 #1复制
1
2 3
输出 #1复制
6
输入 #2复制
2
114 514
1919 180
输出 #2复制
8388223
16580700
说明/提示
【样例解释 #1】
当 n=2,l=3,a 取 {1,2,1} 的任一排列时可以得到最大值,为 (12)+(11)+(21)=6,易证明此时原式有最大值。

【数据范围与约定】

测试点编号    TleT≤    nlen≤    llel≤
15     200    10
5
6     10^5
10^12    2
7     10^5
10^12    3
810     10^5    10^12
10^5
对于 100% 的数据,满足 1≤T≤5×10^51≤n≤10^122≤l≤10^5。

 

 

 

思路:首先要知道异或运算是什么东西,就是将两个数转化成二进制数,然后对位比较,0 xor 1 = 1,0 xor 0 = 0,1 xor 1 = 0。那么这个题的思路其实也不难想,当一个数循环到i的时候,它既要跟前面的数,而且当它当j的时候也要跟后面的数比较,相当于这个数要跟所有的数都比较一遍。假设一共有x个1,因为一共有l个数,所以有l-x个0。当当前这一位是1的时候,那么可以跟l-x个0配对贡献。同理,如果这一位是0的话,那么就可以跟x个1配对贡献。那么贡献就是2^k*x*(l-x),根据小学奥数+感性理解,当x=l-x时贡献最大,那么代码就很简单了。

代码:

#include<bits/stdc++.h>
using namespace std;
int T;
long long x,y;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>x>>y;
        long long t=y>>1;
        if(x==1)//特判,如果数列里只有1,那么异或值肯定是0
        {
            cout<<0<<endl;
            continue;
        }
        long long now=1LL<<40,res=0;//开一个很大的数,然后往下找
        while(now)
        {
            now>>=1;//每一个对应位置上的1和0可以贡献2^k值
            if(x<now) continue;//如果在范围外肯定不行
            res+=now*t*(y-t);//可以的话肯定是0和1对半开值最大,而且要乘以对应位置上的值
        }
        printf("%lld
",res%1000000007);//最后要取模别忘了
    }
    return 0;
}
原文地址:https://www.cnblogs.com/57xmz/p/13114784.html