DP 与计数
A
CF294C Shaass and Light
考虑初始已点亮的灯将所有剩下的灯划分成的连续段。除开头结尾外,每个长为
代码
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int P = 1e9 + 7;
int n, m;
int a[1005];
inline int qpow(int x, int y) {
if (y <= 0)
return 1;
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
int inv[1005], ifac[1005], fac[1005];
inline int C(int n, int m) { return (n < m ? 0 : fac[n] * ifac[m] % P * ifac[n - m] % P); }
signed main() {
cin >> n >> m;
inv[0] = ifac[0] = fac[0] = inv[1] = ifac[1] = fac[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (P - P / i) * inv[P % i] % P;
fac[i] = fac[i - 1] * i % P;
ifac[i] = ifac[i - 1] * inv[i] % P;
}
for (int i = 1; i <= m; i++) cin >> a[i];
sort(a + 1, a + m + 1);
int res = n - m;
int ans = C(res, a[1] - 1);
res -= (a[1] - 1);
ans = ans * C(res, n - a[m]) % P;
res -= (n - a[m]);
for (int i = 2; i <= m; i++) {
ans = ans * qpow(2, a[i] - a[i - 1] - 2) % P;
ans = ans * C(res, a[i] - a[i - 1] - 1) % P;
res -= (a[i] - a[i - 1] - 1);
}
cout << ans;
return 0;
}
B
CF1753C Wish I Knew How to Sort
发现最终序列一定是前面全是
代码
#include <iostream>
#define int long long
using namespace std;
const int P = 998244353;
inline int qpow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
int dp[200005];
int a[200005];
signed main() {
int tc;
cin >> tc;
while (tc--) {
int n, k = 0;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], a[i] ^= 1, k += a[i];
for (int i = 1; i <= n; i++) a[i] += a[i - 1];
dp[a[k]] = 0;
int S = n * (n - 1) / 2;
for (int i = a[k] + 1; i <= k; i++) dp[i] = (dp[i - 1] + S % P * qpow((k - i + 1) * (k - i + 1), P - 2) % P) % P;
cout << dp[k] << "\n";
}
return 0;
}
C
CF1657E Star MST
题目限制等价于以
代码
#include <iostream>
#define int long long
using namespace std;
const int P = 998244353;
int f[255][255];
int g[255][255];
int inv[255], ifac[255], fac[255];
inline void Cpre(int n) {
inv[0] = ifac[0] = fac[0] = inv[1] = ifac[1] = fac[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (P - P / i) * inv[P % i] % P;
fac[i] = fac[i - 1] * i % P;
ifac[i] = ifac[i - 1] * inv[i] % P;
}
}
inline int C(int n, int m) { return n < m || n < 0 || m < 0 ? 0 : fac[n] * ifac[m] % P * ifac[n - m] % P; }
inline int qpow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
signed main() {
int n, K;
cin >> n >> K;
Cpre(max(n, K));
f[1][0] = 1;
for (int i = 0; i <= K; i++) g[1][i] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= K; j++) {
for (int t = 1; t < i; t++)
f[i][j] = (f[i][j] + g[t][j - 1] * C(n - t, i - t) % P * qpow(K - j + 1, (i - t) * (i + t - 3) / 2) % P) % P;
g[i][j] = (g[i][j - 1] + f[i][j]) % P;
}
}
cout << g[n][K];
return 0;
}
D
CF660E Different Subsets For All Tuples
首先,空子序列共有
其次,考虑对每种子序列计算贡献。发现长度相同的子序列的贡献是相同的,于是只需要枚举子序列的长度
于是就可以一遍循环过去求了。
代码
#include <iostream>
#define int long long
using namespace std;
const int P = 1e9 + 7;
int qpow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
signed main() {
int n, m;
cin >> n >> m;
int ans = qpow(m, n);
for (int i = 0; i < n; i++) ans = (ans + qpow(m, n - i) * qpow(2 * m - 1, i) % P) % P;
cout << ans;
return 0;
}
E
CF785D Anton and School - 2
考虑在每个合法子序列的最后一个前括号处计算贡献。设这个点前面(含这个点)有
代码
#include <iostream>
#define int long long
using namespace std;
const int P = 1e9 + 7;
int inv[200005], ifac[200005], fac[200005];
int a[200005];
int b[200005];
void Cpre(int n) {
inv[0] = ifac[0] = fac[0] = inv[1] = ifac[1] = fac[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (P - P / i) * inv[P % i] % P;
fac[i] = fac[i - 1] * i % P;
ifac[i] = ifac[i - 1] * inv[i] % P;
}
}
inline int C(int n, int m) { return fac[n] * ifac[m] % P * ifac[n - m]; }
signed main() {
string str;
cin >> str;
int n = str.size();
Cpre(n);
str = ' ' + str;
for (int i = 1; i <= n; i++) a[i] = a[i - 1] + (str[i] == '(');
for (int i = n; i; i--) b[i] = b[i + 1] + (str[i] == ')');
int ans = 0;
for (int i = 1; i <= n; i++) {
if (str[i] == '(')
ans = (ans + C(a[i] + b[i] - 1, a[i])) % P;
}
cout << ans << "\n";
return 0;
}
F
我们考虑枚举从哪个点开始扩展。然后考虑对于每一对数算出其成为逆序对的概率,加起来搞一搞即可。以当前开始扩展的点为根,则对于两个点,若其中一个是另一个的祖先,则这两个点的扩展顺序就已经被确定了。否则考虑它们的 LCA。在它们的 LCA 被扩展到之前,所有的扩展对这两个点都没有影响。在扩展到它们的 LCA 之后,每一步相当于以
代码
#include <iostream>
#include <string.h>
#define int long long
using namespace std;
const int P = 1e9 + 7;
int n;
int head[205], nxt[405], to[405], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int dp[205][205];
inline int qpow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
int son[205], dep[205], top[205], sz[205], f[205];
void dfs1(int x, int fa, int d) {
dep[x] = d;
f[x] = fa;
sz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v != fa) {
dfs1(v, x, d + 1);
sz[x] += sz[v];
if (sz[v] > sz[son[x]])
son[x] = v;
}
}
}
void dfs2(int x, int t) {
top[x] = t;
if (!son[x])
return;
dfs2(son[x], t);
for (int i = head[x]; i; i = nxt[i]) {
int v = to[i];
if (v != son[x] && v != f[x])
dfs2(v, v);
}
}
int LCA(int x, int y) {
while (top[x] ^ top[y]) (dep[top[x]] < dep[top[y]]) ? (y = f[top[y]]) : (x = f[top[x]]);
return (dep[x] < dep[y] ? x : y);
}
int ans;
void Solve(int x) {
memset(son, 0, sizeof son);
dfs1(x, 0, 1);
dfs2(x, x);
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
int t = LCA(i, j);
ans += dp[dep[j] - dep[t]][dep[i] - dep[t]];
ans -= (ans >= P ? P : 0);
}
}
}
signed main() {
cin >> n;
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
add(u, v);
add(v, u);
}
for (int i = 1; i <= n; i++) dp[i][0] = 0, dp[0][i] = 1;
int inv2 = qpow(2, P - 2);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) * inv2 % P;
}
for (int i = 1; i <= n; i++) Solve(i);
cout << ans * qpow(n, P - 2) % P;
return 0;
}
H
CF1437F Emotional Fishermen
考虑最终的排列一定是形如
代码
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int P = 998244353;
int pos[5005];
int a[5005];
int dp[5005];
int inv[5005], ifac[5005], fac[5005];
void Cpre(int n) {
inv[0] = ifac[0] = fac[0] = inv[1] = ifac[1] = fac[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (P - P / i) * inv[P % i] % P;
fac[i] = fac[i - 1] * i % P;
ifac[i] = ifac[i - 1] * inv[i] % P;
}
}
inline int A(int n, int m) { return n < m || n < 0 || m < 0 ? 0 : fac[n] * ifac[n - m] % P; }
signed main() {
int n;
cin >> n;
Cpre(n);
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) {
pos[i] = 0;
while (pos[i] <= i && a[pos[i]] * 2 <= a[i]) ++pos[i];
}
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; a[j] * 2 <= a[i]; j++)
dp[i] = (dp[i] + dp[j] * A(n - pos[j] - 1, pos[i] - pos[j] - 1) % P) % P;
}
cout << (a[n] < a[n - 1] * 2 ? 0 : dp[n]);
return 0;
}
J
CF1626F A Random Code Problem
考虑对一次操作计算贡献。可以直接把每个数求和除以
代码
#pragma GCC optimize(2)
#include <iostream>
#define int long long
using namespace std;
const int P = 998244353;
int a[10000005];
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline int qpow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1)
ret = ret * x % P;
y >>= 1;
x = x * x % P;
}
return ret;
}
int dp[18][720725];
inline void add(int& x, int y) { x += y, x -= (x >= P ? P : 0); }
signed main() {
int n, x, y, k, M;
cin >> n >> a[1] >> x >> y >> k >> M;
for (int i = 2; i <= n; i++) a[i] = (a[i -1] * x + y) % M;
int p = 1;
for (int i = 1; i < k; i++) p = p * i / gcd(p, i);
int ans = 0, s = 0;
for (int i = 1; i <= n; i++) s += (a[i] / p) * p, dp[0][a[i] % p]++;
int invn = qpow(n, P - 2);
ans = k * s % P * invn % P;
for (int i = 0; i < k; i++) {
int tmp = 0;
for (int j = 0; j < p; j++) {
add(dp[i + 1][j - j % (i + 1)], invn * dp[i][j] % P);
add(dp[i + 1][j], (P + 1 - invn) * dp[i][j] % P);
tmp = (tmp + j * dp[i][j] % P) % P;
}
ans = (ans + tmp * invn % P) % P;
}
cout << ans * qpow(n, k) % P << "\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?