C. Moamen and XOR

C、Moamen and XOR

题意:

给定一个n和k,让你求有多少个满足下列条件的a数组(其中 0 ≤ a i < 2 k 0≤a_i<2^k 0ai<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+......+Cnn=2n1。证明如下:
请添加图片描述

此时我们需要特判两种情况,当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} ci1如果当前这位 &运算已经大于⊕运算了,那么后面无论怎么取都是左边的更大了,所以此时后方的方案数为 2 ( k − i ) ∗ n 2^{(k-i)*n} 2(ki)n,所以此时大于的情况的总方案数为: ∑ i = 1 k ( c i − 1 ∗ 2 ( k − i ) ∗ n ) ∑_{i=1}^{k}(c^{i-1}*2^{(k-i)*n}) i=1k(ci12(ki)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;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值