P4456 CQOI2018 交错序列 - 洛谷 (luogu.com.cn)


时间复杂度线性。
cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7 + 10;
int fac[N], inv[N], P;
int qpow(int a, int b) {
int c = 1;
while (b) {
if (b & 1) c = 1ll * c * a % P;
a = 1ll * a * a % P;
b >>= 1;
}
return c;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, a, b;
cin >> n >> a >> b >> P;
fac[0] = 1;
for (int i = 1; i <= n + 1; i ++) {
fac[i] = 1ll * fac[i - 1] * i % P;
}
inv[n + 1] = qpow(fac[n + 1], P - 2); // (n+1)! 的逆元
for (int i = n; i >= 0; i --)
inv[i] = 1ll * inv[i + 1] * (i + 1) % P;
int ans = 0;
// 枚举 1 的个数 i(即 y = i)
for (int i = 0; i <= n; i ++) {
// 交错序列中 1 不相邻,恰好有 i 个 1 的方案数为 C(n - i + 1, i)
// 需要满足 i <= n - i + 1,即 2i <= n + 1,否则组合数为 0
if (i <= n - i + 1) {
// 组合数 C(n-i+1, i) = fac[n-i+1] * inv[i] * inv[n-2i+1] mod m
// 这里 n-(i-1) = n-i+1,n-(i-1)-i = n-2i+1
int comb = 1ll * fac[n - i + 1] * inv[i] % P * inv[n - i + 1 - i] % P;
// 特征值:x = n - i(0 的个数),y = i(1 的个数)
// 贡献 = 方案数 * (n-i)^a * i^b
int term = 1ll * comb * qpow(n - i, a) % P * qpow(i, b) % P;
ans = (ans + term) % P;
}
}
cout << ans << "\n";
return 0;
}