洛谷 P6599 「EZEC-2」异或
题目描述 有 T 组询问,每次给定两个正整数 n,l, 你需要构造一个长度为 l 的正整数序列 a(编号从 1 至 l),且满足 ∀i∈[1,l],都有 ai∈[1,n]。 求: i=1∑l j=1∑i−1ai⊕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} 的任一排列时可以得到最大值,为 (1⊕2)+(1⊕1)+(2⊕1)=6,易证明此时原式有最大值。 【数据范围与约定】 测试点编号 T\leT≤ n\len≤ l\lel≤ 1∼5 200 10 5 6 10^5 10^12 2 7 10^5 10^12 3 8∼10 10^5 10^12 10^5 对于 100% 的数据,满足 1≤T≤5×10^5,1≤n≤10^12,2≤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\n",res%1000000007);//最后要取模别忘了 } return 0; }