C、Moamen and XOR
题意:
给定一个n和k,让你求有多少个满足下列条件的a数组(其中
0
≤
a
i
<
2
k
0≤a_i<2^k
0≤ai<2k)
a1&a2&a3&…&an≥a1⊕a2⊕a3⊕…⊕an
思路:
我们首先考虑两边相等的情况。此时两边的所有位都相等,那么我们从最高位向最低位依次考虑。此时当前这位若要相等,只有两种可能,即都为1 1或都为0 0。那么我们首先考虑都为0的这种情况,我们注意到此时
a
i
a_i
ai的当前这位必须出现偶数次1才可以让当前这位的异或和为0,即出现次数为:
C
n
0
+
C
n
2
+
.
.
.
.
.
.
+
C
n
小
于
n
的
最
大
偶
数
=
2
n
−
1
C_n^0+C_n^2+......+C_n^{小于n的最大偶数}=2^{n-1}
Cn0+Cn2+......+Cn小于n的最大偶数=2n−1。证明如下:
此时我们需要特判两种情况,当n为偶数时,即n个1异或起来为0,此时是大于而不是等于的情况,所以我们把这种情况先排除出去,后面再单独计算这种情况(因为此时左边最高位已经大于右边最高位了,因此后面元素其实可以任取)。而当n为奇数时,n个1异或起来为1,恰好两边也相等,因此n为奇数时,要加上这种方案(可能有人会疑问,再加上一个1难道不会重复计算吗?其实是不会的,因为我们之前考虑的是1取偶数个的情况,并没有包括这种1取奇数的情况)。我们这里设c为这一位相等的概率,那么全部位相等的概率就是
c
k
c^k
ck。
然后我们再考虑前面提到的n为偶数的情况。设当前这位为i,由于前面的若干位是可以取任意相等的情况,所以前面的方案数为
c
i
−
1
c^{i-1}
ci−1如果当前这位 &运算已经大于⊕运算了,那么后面无论怎么取都是左边的更大了,所以此时后方的方案数为
2
(
k
−
i
)
∗
n
2^{(k-i)*n}
2(k−i)∗n,所以此时大于的情况的总方案数为:
∑
i
=
1
k
(
c
i
−
1
∗
2
(
k
−
i
)
∗
n
)
∑_{i=1}^{k}(c^{i-1}*2^{(k-i)*n})
∑i=1k(ci−1∗2(k−i)∗n),此时与前面相等的方案数加起来就是总的方案数了。
代码:
#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std;
#define int long long
#define fi first
#define se second
#define endl '\n'
#define PII pair<int,int>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
const int N=1e6+5,mod=1e9+7;
int h[N],e[N],nx[N],idx;
int k,T,t,n,m,ans,cnt;
int a[N];
bool vis[N];
priority_queue <int,vector<int>,greater<int> > q;
int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res%mod;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)
{
cin>>n>>k;
int c=ksm(2,n-1);
if(n&1) c=(c+1)%mod;
else c=(c-1+mod)%mod;
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%mod)%mod;
}
}
cout<<ans<<endl;
}
return 0;
}