Solution -「AGC 039F」Min Product Sum
Link.
对于所有 的矩阵 , , 求
, 为素数.
很有想象力的状态设计, 不愧是 AGC. (
(下令题面中 为 , 另作他用.) 第一步是技巧性的转化: 把所有 "权值" 构造成方案数, 将问题变为纯纯的方案数计数问题. 这里不难将 的权值描述为满足 的矩阵 的数量. 我们就是要求所有 的方案.
令 表示考虑了所有 中最大值 行列以及 中所有最小值 的行列, 总共有 行被考虑到, 列被考虑到时, 所有可确定位置的方案数之和. 注意, 对于每个位置, 当其第一次被行 (或列) 考虑到时, 我们先确定其 中的值; 当其接着被列 (或行) 考虑到时, 我们再确定其 中的值.
转移不妨先填出最小值为 的行, 再填出最小值为 的列.
填行, 对于新被考虑到的一行:
- 有 个位置在填 值. 因为本行最小值钦定为 , 所以方案数为 .
- 有 个位置在填 值. 同理, 方案数为 (容斥使得至少有一个 , 限定新行上取出 的行最大值为 ).
填列, 对于新被考虑到的一列:
- 有 个位置在填 值. 方案数为 (容斥使得至少有一个 , 限定新列上取出 的列最大值为 ).
- 有 个位置在填 值. 方案数为 .
两个不那么对称的容斥限定使得 "新建行列上有 [ 的最大值 / 的最小值 / 二者]" 三种情况都能唯一地取出来. 那么枚举每次新建的行列数量, 可以做到 转移求解.
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
const int MAXN = 100;
int n, m, d, P, bino[MAXN + 5][MAXN + 5], f[2][MAXN + 5][MAXN + 5];
inline int mul(const int u, const int v) { return 1ll * u * v % P; }
inline void subeq(int& u, const int v) { (u -= v) < 0 && (u += P); }
inline int sub(int u, const int v) { return (u -= v) < 0 ? u + P : u; }
inline void addeq(int& u, const int v) { (u += v) >= P && (u -= P); }
inline int add(int u, const int v) { return (u += v) < P ? u : u - P; }
inline int mpow(int u, int v) {
int ret = 1;
for (; v; u = mul(u, u), v >>= 1) ret = mul(ret, v & 1 ? u : 1);
return ret;
}
inline void init() {
bino[0][0] = 1;
rep (i, 1, MAXN) {
bino[i][0] = 1;
rep (j, 1, i) bino[i][j] = add(bino[i - 1][j - 1], bino[i - 1][j]);
}
}
int main() {
scanf("%d %d %d %d", &n, &m, &d, &P);
init();
f[0][0][0] = 1;
rep (i, 1, d) {
auto fcur = f[0], fnex = f[1];
rep (j, 0, n) rep (k, 0, m) {
if (int& cur = fcur[j][k]) {
int pw = 1, c = mul(sub(mpow(i, m - k),
mpow(i - 1, m - k)), mpow(d - i + 1, k));
rep (l, 0, n - j) {
addeq(fnex[j + l][k], mul(mul(bino[repl][l], pw), cur));
pw = mul(pw, c);
}
cur = 0;
}
}
fcur = f[1], fnex = f[0];
rep (j, 0, n) rep (k, 0, m) {
if (int& cur = fcur[j][k]) {
int pw = 1, c = mul(sub(mpow(d - i + 1, j),
mpow(d - i, j)), mpow(i, n - j));
rep (l, 0, m - k) {
addeq(fnex[j][k + l], mul(mul(bino[repl][l], pw), cur));
pw = mul(pw, c);
}
cur = 0;
}
}
}
printf("%d\n", f[0][n][m]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2021-07-20 Solution -「UNR #5」「UOJ #671」诡异操作
2021-07-20 Solution -「多校联训」区间