Moamen和Ezzat在玩游戏。它们创建了一个数组a,包含n个非负整数,其中每个元素都小于2如果a & a2 & a3 &…&an 2 a1 Φa2 Φα3…an。这里&表示按位的AND操作,而表示按位的异或操作。请计算Moamen数组a的中奖次数。由于结果可能非常大,打印对1 000 000 007(10°+7)模的值。输入第一行包含一个整数t (1 <t<5)——测试用例的数量。每个测试用例包含一行,包含两个整数n和k (1 <n<2- 105,0 <k <2-105)。输出对于每个测试用例,打印一个值——Moamen获胜的不同数组的数量。打印模1 000 000 007(10°+7)的结果。
Example
input
Copy
3 3 1 2 1 4 0
output
Copy
5 2 1
请注意在第一个例子中,n = 3, k = 1。结果,所有可能的数组(0,0,0),[0,0,1],(0,1,0),(1,0,0)[1 1 0],[0,1,1],[1,0,1],(1,1,1)。Moamen获胜只有5:(0,0,0),(1,1,0),(0,1,1),[1,0,1],(1,1,1)。
题解:
由于是与和异或,所有我们转换成二进制位的形式来看这道题
对于二进制位某一位左边大于等于右边的情况
关键是1出现的次数,只有1出现的次数为偶数时,左边才会大于等于右边
情况数为 c = Cn0 + Cn2 + Cn4 .... + Cnx x为n之前的最大偶数
根据二项式定理
Cn0 + Cn1 + Cn2 + Cn3 .. Cnn = 2^n
易得(n奇偶都一样)
c = 2^(n-1) (证明过程建议网上找)
1.如果n为奇数
那么n全为1,左边等于右边,这也是一种情况c++
由于k位,所有相等的情况为c^k (n为奇数时,最多只有两边相等的情况)
2.如果n为偶数
由于n全为1,左边大于右边(和奇数情况不同),我们先减去这种情况c--,原因等会解释
所有相等的情况为c^k
接着我们来算左边大于右边的情况
我们假设从高到低枚举每一位i,这一位使他全为1,
对于i之前的,我们让他们全都相等,情况为x = c^(i-1)
对于i之后的,由于第i位以及大于右边了,所有i之后的随便取 y = 2^(k-i)
ans += x*y
#include<iostream>
#include<string>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
int a[300005];
int n,m = 1e9 + 7;
int ksm(int x,int p)
{
int ans = 1;
while(p)
{
if(p&1)
ans = ans*x%m;
x = x*x%m;
p /= 2;
}
return ans%m;
}
void solve()
{
int k;
cin >> n >> k;
int c = ksm(2,n - 1);
if(n&1)
c = (c + 1)%m;
else
c = (c - 1 + m)%m;
int ans = ksm(c,k);
if(n%2 == 0)
{
for(int i = 1;i <= k;i++)
{
int x = ksm(c,i - 1);
int y = ksm(2,(k - i)*n);
ans = (ans + x*y%m)%m;
}
}
cout << ans <<"\n";
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
// scanf("%lld",&t);
while (t--)
{
solve();
}
return 0;
}