C. Moamen and XOR(组合数学)

Problem - C - Codeforces

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值