P3214 [HNOI2011] 卡农
形式化题意
有
step 1
考虑偶数,我们想到异或操作,看到组合套组合,我们想到装压,两个一叠加,就成了第一步,将组合抽象化,变成一个状态,而偶数就是所有状态异或和为0
step 2
考虑到是组合套组合,那么状态便被锁的很死,所以尝试变成排列套组合,最后除序即可
step 3
排列套组合变成了我们熟悉的装压
step 4
其实既使这样转移也很复杂(这个要是不信,你自己正着做一遍吧),考虑用容斥,那么将分为一下两点:
1. 全部的方案数
考虑到由于当前的状态有前面的状态来得到,并且是唯一指定,所以只要考虑前面的编排,由于是排列套组合,所以是
2. 不合法的方案数
不合法的有两种:
- 在当前状态之前就已经结束了,那么当前状态肯定无法结束,因为组合一定要选,所以这里要减去的方案数为
即在 就已经结束了的 - 很奇怪,为什么只要减去
的呢,因为这里还要剪掉一些,以上问题来看,如果在 (这个只是瞎列数) 的时候结束那么到 这里必然存在重复,所以这种不合法就处理重复(不要听我瞎逼逼,这里只是解释一下上面的,下面的才是重点),那么除了以上问题的角度,还有一个是如果出现重复,必然删掉两个数后任然是一个完整的状态(即可以用 表示的状态),所以这种不合法的方案首先有一个 ,那么会有多少种与前面的重复的可能?有 种,最后有多少重复的数的可能呢?有 为什么要减 因为前面有 个不与它相同,不然早就判掉了,只有删掉,才不会判重,那么这题就结束了。
step 5
真的结束了吗?其实一直遗留了一个问题,就是排列数怎么算,由于
相当于是每
code
#include <iostream> using namespace std; using ll = long long; const int MaxN = 2e6 + 10, mod = 1e8 + 7; ll qpow(ll a, ll b) { ll res = 1; for (ll i = 1; i <= b; (b & i) && (res = res * a % mod), a = a * a % mod, i <<= 1) { } return res; } ll f[MaxN], ani[MaxN], n21, n, m, ma = 1; int main() { cin >> n >> m, f[f[0] = 1] = 0, n21 = ((qpow(2, n) - 1) % mod + mod) % mod, ani[ani[0] = 1] = n21; for (int i = 2; i <= m; i++) { ma = ma * i % mod; ani[i] = ani[i - 1] * (((n21 - i + 1) % mod + mod) % mod) % mod; f[i] = ((((ani[i - 1] - f[i - 1]) % mod + mod) % mod - (f[i - 2] * (i - 1) % mod * ((n21 - i + 2) % mod + mod) % mod) % mod) % mod + mod) % mod; } cout << f[m] * qpow(ma, mod - 2) % mod << endl; return 0; }
最短的代码,最无语的思路,这思路我打死都想不到
本文作者:yabnto
本文链接:https://www.cnblogs.com/ybtarr/p/18340206
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步