CF1557C(组合数,位运算)
作者:互联网
CF1557C(组合数,位运算)
题意
给出序列长度 \(n\) ,取值范围 \([0,2^k - 1]\) 。
求满足 \(a_1 \& a_2 \& a_3 ... \& a_n \ge a_1 \oplus a_2 \oplus ... \oplus a_n\) 的方案数。
思路
先分奇偶讨论。
当 \(n\) 为奇数时,只可能使得不等式等号成立。大于号总不可能成立。因此考虑取等方案。对某一位,操作后都为0或1。
则对任意一个二进制位有: \((C_n^0+C_n^2+C_n^4+...+C_n^{n-1})+C_n^n = 2^{n-1}+1\)
当 \(n\) 为偶数时,如果使得等号成立。操作后二进制位都为0。
则对任意一个二进制位有:\((C_n^0+C_n^2+C_n^4+...+C_n^{n})-C_n^n=2^{n-1}-1\)。
考虑使得大于号成立条件。
我们可以将结果二进制为分为三类。分别是最高位与操作为1的位置 \(i\) , \([0,i-1]\) 和 \([i+1,k-1]\)。
\(i\) 位上一定全1,总方案为1。\([0,i-1]\) 全 \(0\) ,用求等号时公式可算,\([i+1,k-1]\) 任意。
则对第 \(i\) 位有:\((2^{n-1}-1)^i*(2^n)^{k-i-1}\) 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<iomanip>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
int ksm(int a,int b) {
int ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void solve()
{
int n,k; cin >> n >> k;
ll ans = 0;
// 1111 X0000YYY
// X: 0000 C()
// n % 2 == 0
// 11111 X00000Y
// X :0 Y :0/1 C(n,2k) (0~n) 2k != n
// [0,k] i[i-1,0] C(i-1,j) * pow(pow(2,n)),i - j)
// A = B C(n,2k)
ans = ksm(ksm(2,n - 1) + ((n & 1) ? 1 : -1),k);
if(n % 2 == 0) {// [0,k - 1]
// [0,i-1]: 0 [i] :1 [i+1,k - 1]:0/1
rep(i,0,k - 1) {
ans = (ans + ksm(ksm(2,n - 1) - 1,i) * ksm(ksm(2,n),k - i - 1) % mod) % mod;
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
solve();
return 0;
}
标签:CF1557C,运算,组合,int,long,ans,ksm,include,define 来源: https://www.cnblogs.com/Mxrush/p/16426435.html