codeforces 1557 C Moamen and XOR
题目标签
递推、分类讨论
题目大意
有一个由 n n n个大小不超过 2 k 2^k 2k的非负整数组成的数组 a a a ,问有多少组 a a a满足条件 a 1 & a 2 & a 3 … … & a n ≥ a 1 ⊕ a 2 ⊕ a 3 … … ⊕ a n {a_1}\&{a_2}\&{a_3}……\&{a_n}\geq{a_1}⊕{a_2}⊕{a_3}……⊕{a_n} a1&a2&a3……&an≥a1⊕a2⊕a3……⊕an
题目分析
这道题肯定先是将其转化为二进制的 0 0 0和 1 1 1,这样结果最多会有 k k k位
我们现在考虑这 n n n个数进行与运算和异或运算之后的结果
不难分析得出,只要有偶数个 1 1 1进行异或运算,最后结果就是 0 0 0,这样无论与运算的结果是什么,都满足题目条件
这样我们对 n n n的奇偶性进行分类讨论
首先考虑 n n n为奇数的情况
如果 n n n个数中有偶数个 1 1 1,则必定会有 0 0 0存在,这样n个数与运算结果必为 0 0 0,而异或结果必为 0 0 0
如果 n n n个数中有奇数个 1 1 1,则需要考虑是否有 0 0 0存在
如果没有 0 0 0存在,即 n n n个数全为 1 1 1,则与运算结果为 1 1 1,异或结果也为 1 1 1
如果有 0 0 0存在,即 n n n个数不全为 1 1 1,则与运算结果为 0 0 0,异或结果为 1 1 1
我们发现,当 n n n为奇数的时候,不存在 a 1 & a 2 & a 3 … … & a n > a 1 ⊕ a 2 ⊕ a 3 … … ⊕ a n {a_1}\&{a_2}\&{a_3}……\&{a_n}>{a_1}⊕{a_2}⊕{a_3}……⊕{a_n} a1&a2&a3……&an>a1⊕a2⊕a3……⊕an的情况
所以我们需要这 k k k位均满足与运算结果等于异或运算结果
总共有 n n n个数,存在 2 n 2^n 2n种可能性,其中 1 1 1的个数为奇数和偶数的概率相同,故每一位有偶数个 1 1 1的情况有 2 n − 1 2^{n-1} 2n−1种,再加上全为 1 1 1这一种情况,每一位有 2 n − 1 + 1 2^{n-1}+1 2n−1+1种可能性, k k k位总共就有 ( 2 n − 1 + 1 ) k (2^{n-1}+1)^k (2n−1+1)k种可能性
再考虑 n n n为偶数的情况
如果 n n n个数中有奇数个 1 1 1,则必定会有 0 0 0存在,这样n个数与运算结果必为 0 0 0,而异或结果为 1 1 1,不满足条件
如果 n n n个数中有偶数个 1 1 1,则需要考虑是否有 0 0 0存在
如果没有 0 0 0存在,即 n n n个数全为 1 1 1,则与运算结果为 1 1 1,异或结果为 0 0 0
如果有 0 0 0存在,即 n n n个数不全为 1 1 1,则与运算结果为 0 0 0,异或结果为 0 0 0
我们定义一个函数 f ( x ) f(x) f(x)为二进制有 x x x位的满足条件的组数
我们从第 k k k位开始考虑
如果第 k k k位的 n n n个数全为 1 1 1,那么后面位置的数无论是多少,都满足题目条件,这样后面的数有 k − 1 k-1 k−1位,共 n n n个数,那么总共有 ( 2 k − 1 ) n (2^{k-1})^n (2k−1)n种可能性
如果第 k k k位的 n n n个数不全为 1 1 1但是有偶数个 1 1 1,那我们需要算出满足此情况的种类数总共有 ( 2 n − 1 − 1 ) (2^{n-1}-1) (2n−1−1),再乘上第 k − 1 k-1 k−1位种类数,即 f ( k − 1 ) f(k-1) f(k−1),最终递归到第 1 1 1位,第 1 1 1位需要满足偶数个 1 1 1即可
综上,当 n n n为偶数的时候 f ( k ) = ( 2 n − 1 − 1 ) f ( k − 1 ) + ( 2 k − 1 ) n f(k)=(2^{n-1}-1)f(k-1)+(2^{k-1})^n f(k)=(2n−1−1)f(k−1)+(2k−1)n结果递归即可
记得要快速幂取模
AC代码
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
ll T,n,k;
typedef long long ll;
ll mod = 1e9+7;
ll ans;
ll fast_pow(ll a,ll b) {
ll ans = 1;
ll base = a%mod;
while(b) {
if(b&1)
ans = (ans*base)%mod;
b>>=1;
base = (base*base)%mod;
}
return ans ;
}
int main() {
cin>>T;
while(T--) {
cin>>n>>k;
if(k==0) {
cout<<1<<endl;
continue;
}
if(n&1) {
ans = fast_pow(fast_pow(2,n-1)+1,k);
cout<<ans<<endl;
}
else {
ans = fast_pow(2,n-1);
for(ll i=2;i<=k;i++)
ans = (((fast_pow(2,n-1)-1)*ans)%mod+fast_pow(2,(i-1)*n))%mod;
cout<<ans<<endl;
}
}
}