洛谷 「CF1557C Moamen and XOR」
说句闲话,赛时因为和 @Leasier 聊天导致没写完代码。
\(\texttt{Description}\)
-
给定 \(n\) 和 \(k\),\(n\) 为序列长度,\(k\) 表示序列中的值上限为 \(2^k-1\)。
-
求出有多少种满足 \(a_1\ \mathrm{and}\ a_2\ \mathrm{and}\ a_3\ \mathrm{and}\ \dots\ \mathrm{and}\ a_n\ge a_1\ \mathrm{xor}\ a_2\ \mathrm{xor}\ a_3\ \mathrm{xor}\ \dots\ \mathrm{xor}\ a_n\) 的序列 \(a\),答案对 \(10^9+7\) 取模。
-
多测。
数据范围:\(1\le n\le2\times10^5,0\le k\le2\times10^5\)。
\(\texttt{Solution}\)
-
不难看出 \(k\) 为每个数的二进制的最大位数。
-
对于二进制的每一位分开考虑。
-
令二进制数最高位为第一位,次高位为第二位,以此类推。
-
设 \(p1\) 为 \(a_1\ \mathrm{and}\ a_2\ \mathrm{and}\ a_3\ \mathrm{and}\ \dots\ \mathrm{and}\ a_n\),\(p2\) 为 \(a_1\ \mathrm{xor}\ a_2\ \mathrm{xor}\ a_3\ \mathrm{xor}\ \dots\ \mathrm{xor}\ a_n\)。
-
要满足 \(p1\ge p2\) 的条件,分两种情况讨论:
-
若 \(p1=p2\),那么 \(p1\) 和 \(p2\) 的每一位一定都相等,对于每一位:
-
若为 \(0\):则 \(a_1\) 到 \(a_n\) 的这一位必然至少有一个为 \(0\),且为 \(1\) 的个数有偶数个(因为偶数个 \(1\) 异或结果为 \(0\)),所以方案数为 \(\sum\mathcal{C}_{n}^{i}\) 且 \(i\equiv0\pmod2\) 且 \(i\ne n\)。
-
若为 \(1\):则 \(a_1\) 到 \(a_n\) 的这一位必然全为 \(1\),但如果 \(n\) 为偶数,则这样的情况不成立。当这样的情况成立时,方案数为 \(1\)。
-
-
若 \(p1>p2\),那么一定存在某一位 \(k\) 使得 \(p1\) 的第 \(k\) 位为 \(1\) 且 \(p2\) 的第 \(k\) 位为 \(0\),并且满足 \(p1\) 和 \(p2\) 的 \(1\) 到 \(k-1\) 位都相等,但是只有 \(k\) 为偶数时这种情况才能成立。
-
于是我们可以想到枚举这个 \(k\)。对于每个 \(k\),方案数为前面 \(k-1\) 位都相等的方案数(已在上面讨论过)乘上 \((2^n)^{n-k}\),因为第 \(k\) 位后面的可以随便乱选。
-
-
那么这道题就分析完了,之后套一下柿子就可以了。
时间复杂度:\(\mathcal{O}(n\log n)\)
\(\texttt{Code}\)
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll fac[200005];
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;}
int main() {
init(2e5);
int T;
scanf("%d", &T);
while (T--) {
ll n, k, ans = 0, sum = 0;
scanf("%lld %lld", &n, &k);
for (ll i = 0; i < n; i += 2) sum = (sum + getC(n, i, mod)) % mod;
if (n & 1) ans = (ans + quick_pow(sum + 1, k, mod)) % mod;
else {
for (ll i = 0; i < k; i++) ans = (ans + quick_pow(sum, i, mod) * quick_pow(quick_pow(2, n, mod), k - i - 1, mod) % mod) % mod;
ans = (ans + quick_pow(sum, k, mod)) % mod;
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号