Moamen and XOR --- CF-737-C

排列组合和快速幂的应用
题意:
给你一个数t(0 ≤ \leq t ≤ \leq 5)和t组数据,每组数据包含两个数n和k (1≤n≤2* 1 0 5 10^{5} 105,1≤k≤2* 1 0 5 10^{5} 105)。任选n个数 a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3, … \dots , a n a_n an,每个数的范围在0到 2 k 2^{k} 2k-1,求满足 a 1 a_1 a1 & a 2 a_2 a2 & a 3 a_3 a3 & … \dots & a n a_n an ≥ \geq a 1 a_1 a1 ^ a 2 a_2 a2 ^ a 3 a_3 a3 ^ … \dots ^ a n a_n an的选择方案的个数,答案对 1 0 9 10^9 109+7取模。
Example
input

3
3 1
2 1
4 0

output

5
2
1

思路:
把选择的每一个数看成k位的2进制数,左边运算结果设为L,右边结果设为R。二进制每一位的运算结果只与当前位有关,所以L、R的第i位只与每一个选择的数的第i位有关。
考虑二进制数的每一位,当前位&运算结果为1时,表示选择的所有数该位都为1,此时分为两种情况:n为奇数时,n个1相异或结果为1,n个0相异或结果为0;n为偶数时,n个1相异或结果为0,n个0相异或结果为1。
也就是说,n为奇数时, L i L_i Li ≤ \leq R i R_i Ri,要让L ≥ \geq R成立,只能是 L i L_i Li= R i R_i Ri,分为该位为1和该位为0两种情况,该位为1时,只有一种情况,即所有数该位都为1。该位为0时,把奇数个1变为0即可;n为偶数时,n个数的第i位二进制数都是1,则 L i L_i Li=1且 R i R_i Ri=0,所以只要保证 L i + 1 L_{i+1} Li+1, L i + 2 L_{i+2} Li+2, L i + 3 L_{i+3} Li+3, … \ldots , L k L_{k} Lk R i + 1 R_{i+1} Ri+1, R i + 2 R_{i+2} Ri+2, R i + 3 R_{i+3} Ri+3, … \ldots , R k R_{k} Rk分别相等,而使 L i L_i Li=1, R i R_i Ri=0,L>R便能成立。在n个数的第i位二进制数都是1的基础上把任意偶数个数的第i位变成0,则 L i L_i Li= R i R_i Ri=0。
综上所述,n为奇数时,第i个二进制位的选择有 2 n − 1 + 1 2^{n-1}+1 2n1+1种,一共k位,总共方案数为 ( 2 n − 1 + 1 ) k (2^{n-1}+1)^{k} (2n1+1)k;类比n为奇数的情况,n为偶数时,L=R=0的方案数有 ( 2 n − 1 − 1 ) k (2^{n-1}-1)^{k} (2n11)k种,L>R的方案数有 ∑ i = 1 k ( 2 n − 1 − 1 ) k − i ∗ ( 2 n ) i − 1 \sum_{i=1}^k(2^{n-1}-1)^{k-i}*(2^n)^{i-1} i=1k(2n11)ki(2n)i1种。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,k;
        cin>>n>>k;
        ll p=qpow(2,n-1);
        if(n&1){
            cout<<qpow(p+1,k)<<endl;
            continue;
        }
        else{
            ll res=qpow(p-1,k),s=(p<<1)%mod;
            for(int i=1;i<=k;i++){
                res=(res+qpow(p-1,k-i)*qpow(s,i-1)%mod)%mod;
            }
            cout<<res<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值