Moamen and XOR-CF
Moamen and XOR
题目大意:
M和E玩游戏,有n个不超过2**k的的非负数,M对n个数取&得到p1,E对n个数取^得到p2.若p1>=p2,则M胜利。给定n和k,输出M赢的次数。
**思路:
思考这个问题的时候要先明确n、k代表了什么。可以形象地将其理解为一个“二维矩阵”,k是列数,n是行数。每一列代表每一个二进制位,每一行代表每一个数字。

M赢的条件是p1>=p2,拆分开就是p1>p2和p1==p2。对两种情况深入讨论:
1)p1 == p2:
1a:p1 p2的每一位都是0(二进制位):
对第i位(二进制位),&操作需要在n个数中至少有一个0,^需要有偶数个1就是说要在n位里取偶数位x,就是C(x,n),(x取偶数)种可能性,为了方便把i位为0的可能性记作A。而一个数一共有k位,总可能性为 A**k。
1b:p1 p2每一位都是1: 对第i位,&需要全1,^需要奇数个1 。总结一下,n是奇数。就是说只有n是奇数才有可能出现第i位经过&或^后都是1。
2)p1 > p2:
就是说在1~k位种总能找到一个i,p1[i] == 1 && p2[i] == 0 && (1i-1位完全相等)。只要第i位p1是1,p2是0,不管i+1n怎么变,p1就是大于p2的。当&运算出1时就是说n个数的第i位全是1,当^运算出0时就是说n个数里有偶数个1。两个条件叠加,得出n是偶数的条件。
前i-1位相同的可能性是A**(i-1),i+1~k位可以随便01,那就是2**(k-i),加之有n个数字,可能性变为2**(k-i)*n。综合一下就是A**(i-1) * 2**(k-i)*n.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<bitset>
#include<sstream>
#include<cstdlib>
//#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const ll N = 2*1e5+50;
ll fac[N];
ll n,k,ans,bit_0_psib,T;
inline ll read(){
ll ans = 0;
char c = getchar();
while (!isdigit(c))
c = getchar();
while (isdigit(c)){
ans = ans * 10 + c - '0';
c = getchar();
}return ans;
}
inline void init(ll n){
fac[0] = 1;//初始化阶乘
for(ll i = 1;i <= n; i++)
fac[i] = fac[i-1] * i % mod;
}
inline ll quick_pow(ll a, ll k, ll p) {
ll res = 1;//快速幂
a %= p;
while (k) {
if (k & 1) res = res * a % p;
a = a * a % p;
k >>= 1;
}
return res;
}
inline ll inv(ll x,ll p){//逆元
return quick_pow(x,p-2,p);
}
inline ll getC(ll n,ll m,ll p){//求组合数
return fac[n] * inv(fac[n-m] * fac[m] % p, p) % p;
}
inline ll getA(ll n,ll p){
ll res = 0;
for(ll i = 0;i < n; i+=2){
res = (res + getC(n,i,mod))%mod;
}
return res;
}
int main(){
init(2e5);
T = read();
while(T--){
n = read();
k = read();
ans = 0;
bit_0_psib = getA(n,mod);//一位是0的可能性
if(n&1){
ans = quick_pow(bit_0_psib+1,k,mod);
}else{
for(ll i = 1;i <= k; i++){
ans = (ans + quick_pow(bit_0_psib,i-1,mod) * quick_pow(quick_pow(2,k-i,mod),n,mod)%mod)%mod;
}
ans =(ans + quick_pow(bit_0_psib,k,mod))%mod;
}
printf("%lld\n",ans);
}
}
写在后面:
这类题目一定不能傻傻去模拟,而是要分析小部分的情况。将一个数放到二进制层面去理解。

浙公网安备 33010602011771号