【luogu P3214】卡农(数学)(DP)

卡农

题目链接:luogu P3214

题目大意

有 n 种元素,然后你要选 m 个互不相同的集合,满足里面有元素且在 n 种之间,每种至多一个,且每个元素在偶数个集合中出现过。
问你有多少种选法。

思路

考虑如果没有这些条件,只有互不相同。
那答案就是 A2n1m

考虑加上这个每个元素偶数个集合。
那你这个相当于每种元素是一维,然后要异或得到 0
不过因为你任选都可以(除了 0),所以只要前面 m1 的结果不是 0,你一定可以在 m 的位置调整得到 0
那前面的是 0 减去即可,那这不是递推吗:
fm=A2n1m1fm1

但是问题是你最后调整的这个可能会跟前面的某个一样啊。
考虑再判掉,那考虑跟前面一样的消掉,那剩下的根据条件是 0
那你可以选择跟前面的哪个位置,那个位置是什么数,所以是:
fm=A2n1m1fm1fm2(m1)(2nm+1)

然后 1e8+7 是质数放心弄就行。

代码

#include<cstdio> #define ll long long #define mo 100000007 using namespace std; const int N = 1e6 + 100; int n, m, f[N], jc[N], A[N]; int add(int x, int y) {return x + y >= mo ? x + y - mo : x + y;} int dec(int x, int y) {return x < y ? x - y + mo : x - y;} int mul(int x, int y) {return 1ll * x * y % mo;} int ksm(int x, int y) {int re = 1; while (y) {if (y & 1) re = mul(re, x); x = mul(x, x); y >>= 1;} return re;} int main() { scanf("%d %d", &n, &m); jc[0] = 1; for (int i = 1; i < N; i++) jc[i] = mul(jc[i - 1], i); int n2 = ksm(2, n); A[0] = 1; for (int i = 1; i <= m; i++) A[i] = mul(A[i - 1], dec(dec(n2, 1), i - 1)); f[0] = 1; f[1] = 0; for (int i = 2; i <= m; i++) { f[i] = dec(A[i - 1], add(f[i - 1], mul(f[i - 2], mul(i - 1, dec(n2, i - 1))))); } printf("%d", mul(f[m], ksm(jc[m], mo - 2))); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P3214.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示