原题地址:http://codeforces.com/contest/1557/problem/C
题目大意:
给两个数n和k,问满足 a1 & a2 & a3 … & an >= a1 ^ a2 ^ a3 … ^ an ( 0 <= a[i] <= 2^k )的有多少种不同的数组
思路:
根据位运算,奇数个1异或的结果才是1,偶数个1异或的结果是0;而只有所有数都为1,与的结果才是1,其余情况结果都是0
n为奇数的情况:
对于这种情况,与的结果会始终小于等于异或的结果
(若想当前位置与的结果为1,则需要全为1,此时1有奇数个,异或的结果也必为1)
所以此时我们只需要考虑与和异或相等的情况,只考虑每一位时,有:
1、每个数当前位置都是1(异或和与同为1)
2、每个数当前位置都存在偶数个1,奇数个0(异或和与同为0)
共两种情况
而对于情况2,我们得出的算式为:
x= C n 0 C_{n}^{0} Cn0+ C n 2 C_{n}^{2} Cn2 + C n 4 C_{n}^{4} Cn4 +…+ C n n − 3 C_{n}^{n-3} Cnn−3 + C n n − 1 C_{n}^{n-1} Cnn−1
根据组合数的对称关系( C n n − 1 C_{n}^{n-1} Cnn−1 = C n 1 C_{n}^{1} Cn1),则可以把式子转换成:
x= C n 0 C_{n}^{0} Cn0 + C n 1 C_{n}^{1} Cn1 + C n 2 C_{n}^{2} Cn2 +…+ C n n − 1 2 C_{n}^{\frac{n-1}{2}} Cn2n−1
这时我们可以看出x是第n行组合数的前一半,所以x= 2 n 2 \frac{2^n}{2} 22n, 为2n-1
所以,对于每一位,都存在 2n-1 +1中情况
总共是(2n-1 +1)k 种情况
n为偶数的情况:
先考虑与和异或相等的情况(即每一位存在偶数个1,且不能全是1):
x= C n 0 C_{n}^{0} Cn0 + C n 2 C_{n}^{2} Cn2 + C n 4 C_{n}^{4} Cn4 +…+ C n n − 2 C_{n}^{n-2} Cnn−2 = 2n-1 -1
再考虑与比异或大的情况,即当前位置前面异或和与的结果都相同,当前位置与比异或大(只有全为1这种情况),后面位置随意排列。
那么我们就可以枚举与和异或相等的位置,当第i位相等时:
对于前面相等的位置,每一位都是2n-1 种情况,即(2n-1-1)i-1
对于当前位置,只有一种情况(全是1)
对于后面随便排列的位置,每个数每一位0或1都可,即(2n)k-i
即对每一位都有(2n-1)i-1 *(2n)k-i 种情况
这里枚举相加即可
代码:
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int N=1e5+5;
ll n,k;
ll ksm(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
void solve()
{
cin>>n>>k;
if(n%2==1)
cout<< ksm(ksm(2,n-1)+1,k) <<endl;
else
{
ll ans=ksm(ksm(2,n-1)-1,k);
for(int i=1;i<=k;i++)
ans = (ans + ksm(ksm(2,n-1)-1,i-1) * ksm(ksm(2,n),k-i) %mod)%mod;
cout<<ans<<endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int __=1;
cin>>__;
while(__--)
solve();
return 0;
}