数学做题笔记
P1829 [国家集训队] Crash 的数字表格:推式子。
本质上和 P3768 简单的数学题 没有多大区别,杜教筛筛一下 就能解决了。
顺带一提,P3768 最后推出来是 。(
这里是一如既往的换掉 变成
然后从 里面提出来 ,显然不为 倍数时无贡献,那么变成
然后就可以开始莫反了,哈哈哈。
形式大约是 这样子推。
设 ,
就能得到
同理直接提 ,得到
代回去得到
可以了, 做法到手。下面看一眼 借鉴了 Solution 的 根号复杂度做法。
事实上这个做法的思路只是将枚举因数变成了枚举 也就是乘积
然后把前缀和给提出来预处理就变得非常迅速
就可以愉快地 单次询问求解啦。
P1446 [HNOI2008] Cards:大致是给出三种牌数然后给一堆置换,求方案数。
Burnside 引理板题。直接套上去即可。
这个洗牌就是一个置换群,用类似求环的方法直接求出来置换的循环即可。
求出来之后直接 DP 求解方案数即可~
inline int qinyubo() {
int cnt = 0;
for (int i = sr; ~i; --i) for (int j = sb; ~j; --j)
for (int k = sg; ~k; --k) f[i][j][k] = 0;
for (int i = 1; i <= n; ++i) vis[i] = false;
for (int i = 1; i <= n; ++i) {
if (vis[i]) continue;
int cur = i, curans = 0;
while (!vis[cur])
++curans, vis[cur] = true, cur = to[cur];
siz[++cnt] = curans;
}
f[0][0][0] = 1;
for (int cur = 1; cur <= cnt; ++cur)
for (int i = sr; ~i; --i) for (int j = sb; ~j; --j)
for (int k = sg; ~k; --k) {
if (i >= siz[cur]) (f[i][j][k] += f[i-siz[cur]][j][k]) %= p;
if (j >= siz[cur]) (f[i][j][k] += f[i][j-siz[cur]][k]) %= p;
if (k >= siz[cur]) (f[i][j][k] += f[i][j][k-siz[cur]]) %= p;
}
return f[sr][sb][sg];
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> sr >> sb >> sg >> m >> p;
n = sr + sb + sg;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) cin >> to[j];
(res += qinyubo()) %= p;
}
for (int i = 1; i <= n; ++i) to[i] = i;
(res += qinyubo()) %= p;
(res *= qpow(m + 1, p - 2)) %= p;
cout << res << endl;
return 0;
}
P3197 [HNOI2008] 越狱:哈哈哈哈哈哈哈哈哈哈哈哈题。
考虑不发生越狱的方案数,第一个房间有 种,后面都是 种。
用总方案数减掉不合法数得出答案。
all = qpow(m, n), to = m * qpow(m - 1, n - 1) % md;
res = ((all - to) % md + md) % md;
cout << res << endl;
P4609 [FJOI2016] 建筑师:城市规划。
首先显然可以确定一个最高的建筑,以此为中心,分成左半和右半。
同时可以认为,左半分为了 个段,右半为 。
然后可以将一个可以被看见的建筑理解为一个以其为开头的段。
那么这一段中以其为开头,其余的可以随便排序。
计算答案发现,假设某一段长度为 ,则排列方案数为 。
而一个大小为 的环,排列方案数也恰好为 。
则可以理解为将 个元素分为 个环。
那么答案就是这样,左边右边分一下,一个组合数,然后分一下环,乘起来。
答案即为 。
res
表示第一类斯特林数,c
表示组合数。
inline void init() {
res[0][0] = 1;
for (int j = 1; j <= 5e4; ++j)
for (int i = 1; i <= 2e2; ++i)
res[j][i] = (res[j-1][i-1] + (j - 1) * res[j-1][i]) % p;
for (int i = 0; i <= 2e2; ++i) c[0][i] = 1;
for (int i = 1; i <= 2e2; ++i)
for (int j = 1; j <= 2e2; ++j)
c[i][j] = (c[i-1][j-1] + c[i][j-1]) % p;
}
inline void query() {
cin >> n >> a >> b;
int ans = res[n-1][a+b-2] * c[a-1][a+b-2];
cout << ans % p << endl;
}
CF932E Team Work:推式子题。
本文作者:MistZero
本文链接:https://www.cnblogs.com/MistZero/p/Math-Notes-and-Problems.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步