【2022 省选训练赛 Contest 04 A】permutation(容斥)

permutation

题目链接:2022 省选训练赛 Contest 04 A

题目大意

给你一个排列,然后有一些位置告诉你了。
然后问你有多少种可能使得每个位置的数都不是它位置的编号。

思路

不难看出就一个限制条件 pii,我们可以容斥,每次是至少有 x 个位置出现了 pi=i 的情况。

然后你可以预先搞出有多少个空位 m,以及有多少个数是肯定不能放回自己的位置 mm(自己的位置上有数或者自己已经放在了别的位置)。

然后就是:
i=0mm1iCimm(mi)!
(组合数就是选那些位置放 pi=i,阶乘就是后面的随便放)

代码

#include<cstdio> #define ll long long #define mo 998244353 using namespace std; int n, a[1000001], m, mm; ll ans, jc[1000001], inv[1000001]; bool cant[1000001]; ll C(ll n, ll m) { return jc[n] * inv[m] % mo * inv[n - m] % mo; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); if (a[i] == i) { printf("0"); return 0; } if (!a[i]) m++;//数空的位置数 if (a[i]) cant[a[i]] = cant[i] = 1;//数位置或者数被用了的位置数 } for (int i = 1; i <= n; i++) if (!cant[i]) mm++; jc[0] = 1; for (int i = 1; i <= m; i++) jc[i] = jc[i - 1] * i % mo; inv[0] = inv[1] = 1; for (int i = 2; i <= m; i++) inv[i] = inv[mo % i] * (mo - mo / i) % mo; for (int i= 1; i <= m; i++) inv[i] = inv[i - 1] * inv[i] % mo; ll op = 1; for (int i = 0; i <= mm; i++, op = mo - op) { (ans += op * C(mm, i) % mo * jc[m - i] % mo) %= mo; } printf("%lld", ans); return 0; }

__EOF__

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