题目链接:https://ac.nowcoder.com/acm/contest/54484/B

题意很简单,但是数据范围偏大。

错排公式

首先来推导一下错排公式:

\[D(n) = n!\sum_{k=0}^{n}\frac{(-1)^k}{k!}
\]

设一个函数:

\[S_i表示一个排列中p_i = i的方案数
\]

那么我们可以知道:

\[D(n) = n! - |\cup_{i=1}^{n}S_i|
\]

这个表示所有方案数减去至少有一个位置放对的方案数

现在来考虑一下如何处理后面这个并集,并集往往是不好求的,而交集会好求很多,所以在求并集的时候我们往往采取容斥原理将一个并集转换成诸多交集的加减运算

我们用一个图可以来表示当n = 3的情况:

其中有:

\[|S_1 \cup S_2 \cup S_3| = |S_1| + |S_2| + |S_3| - |S_1 \cap S_2| - |S_1 \cap S_3| - |S_2 \cap S_3| + |S_1 \cap S2 \cap S_3|
\]

扩展一下就可以得到下面的柿子:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}(-1)^k\sum_{1\leq i_1 \leq i_2 \leq ... \leq i_k \leq n}|S_{i1}\cap S_{i2} ... \cap S_{ik}|
\]

然后有:

\[\sum_{1\leq i_1 \leq i_2 \leq ... \leq i_k \leq n}|S_{i1}\cap S_{i2} ... \cap S_{ik}| = C_{n}^{k}(n-k)!
\]

这个表示啥呢,左边这个柿子的含义其实是i1 ~ ik都放对了,其他位置上无所谓的方案数,就等同于在n个位置中选择k个放对,剩下的随便放的方案数。

所以可得下面的柿子:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}(-1)^kC_{n}^{k}(n-k)!
\]

然后化简得:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}\frac{(-1)^k n!}{k!}
\]

然后代回到一开始的答案表达式中:

\[D(n) = n! - \sum_{k=1}^{n}\frac{(-1)^k n!}{k!}
\]

n!提出来,再化简一下得到:

\[D(n) = n! \sum_{k=0}^{n}\frac{(-1)^k}{k!}
\]

回到本题

但是有这个柿子依然不好写这题,这题如果是1e7就可以直接O(n)写了,但是这题是1e9的数据范围,可以考虑一下分段打表(一般要求函数可以递推),但是这个表达式好像不是很好打,我们来分析一下。

首先网上有一个比较有名递推式(证明略):

\[D(n) = (n-1)[D(n - 1) + D(n - 2)]
\]

这个递推需要用到前两项,也就是说我们需要打两个表,然后才可以做,有点麻烦,但是其实是可以只用一项的。

我看网路上都没有用下面这种方式递推的,我在这里写一下。

我们考虑D(n) -> D(n + 1)这样的转移:

\[D(n) = n! \sum_{k=0}^{n}\frac{(-1)^k}{k!}
\]
\[D(n + 1) = (n + 1)! \sum_{k=0}^{n + 1}\frac{(-1)^k}{k!}
\newline = (n + 1)![\sum_{k=0}^{n}\frac{(-1)^k}{k!} + \frac{(-1)^{n + 1}}{(n + 1)!}]
\newline = (n + 1)!\sum_{k=0}^{n}\frac{(-1)^k}{k!} + (-1)^{n + 1}
\newline = (n + 1) \times n!\sum_{k=0}^{n}\frac{(-1)^k}{k!} + (-1)^{n + 1}
\newline = (n+1) \times D(n) + (-1)^{n+1}\]

然后令段大小T = 1e7打表打出D(0), D(T), D(2T) ... D(100T)就好了。

最终的复杂度是O(n)但是常数极小,所以可以过。

Code:

#include <bits/stdc++.h>
#define int long long
using namespace std; const int p = 1e9 + 7, T = 1e7; int a[110] =
{
1,824182295,933713113,474482547,930651136,251064654,637937211,229643390,307311871,448853213,
322273426,398890147,194914852,884947442,154199209,881788023,389699639,733217502,601739182,
372305477,213823357,713959988,498202615,196342945,324300550,154001751,974475946,540773759,
467881322,257531902,598680559,367927849,971346692,94577421,617165552,128327758,503709458,
253566817,820144401,13965056,82358069,805941568,533047638,69430220,686678173,297170813,
34546238,323435423,499126069,487532712,468899710,790590914,581347156,955359050,700529992,
518280890,98592091,64544225,988209678,422603955,40661679,174468756,573631136,757555557,
710709955,775098981,499158883,969149294,880429710,42564126,333697951,522067888,579797877,
528967798,717694718,309384913,31308092,316850320,220854491,878646494,963974981,377654637,
705101053,542246848,466289530,750036412,819636314,688721174,464087273,517164631,256789690,
482685016,276682441,473333947,340221393,762927538,624766601,984537252,977632075,34192646,
402182971,977005016
}; int mo(int x){return (x % p + p) % p;} void solve()
{
int n;cin >> n;
int ans = a[n / T];
for(int i = n / T * T + 1;i <= n; ++ i)ans = mo(ans * i % p + ((i & 1) ? -1 : 1));
cout << ans << '\n';
} void table()
{
int x = 1;//d(0) = 1,这个有点特殊
cout << x << ",";
int cnt = 1;
for(int i = 1;i <= 1e9; ++ i)
{
x = x * i % p;
if(i & 1)x = (x - 1 + p) % p;
else x = (x + 1) % p; if(i % T == 0)
{
cout << x << ",";
cnt ++;
} if(cnt % 10 == 0)
{
cout << '\n';
cnt = 1;
} }
} signed main()
{
table();
solve();
//return 0;
}

【ACM组合数学 | 错排公式】写信的更多相关文章

  1. BZOJ4517:[SDOI2016]排列计数(组合数学,错排公式)

    Description 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 i,则称 i 是稳定的.序列恰好有 m 个数是 ...

  2. HDU 2048:神、上帝以及老天爷(错排公式,递推)

    神.上帝以及老天爷 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  3. HDU——2068RPG的错排(错排公式)

    RPG的错排 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  4. HDU 2068 RPG的错排(错排公式 + 具体解释)

    RPG的错排 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  5. 【BZOJ】4517 [Sdoi2016]排列计数(数学+错排公式)

    题目 传送门:QWQ 分析 $ O(nlogn) $预处理出阶乘和阶乘的逆元,然后求组合数就成了$O(1)$了. 最后再套上错排公式:$ \huge d[i]=(i-1) \times (d[i-1] ...

  6. HDU 1465 不容易系列之一 (错排公式+容斥)

    题目链接 Problem Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 做好"一件"事情尚且不易,若想永远成功而总从不失败,那更是难上 ...

  7. hdu 4535(排列组合之错排公式)

    吉哥系列故事——礼尚往来 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tota ...

  8. HDU——1465不容易系列之一(错排公式)

    不容易系列之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  9. HDU 1465(错排公式)

    不容易系列之一 题意: 一个人要寄n个信封,结果装错了.信纸的编号为1到n,信封的编号为1到n,信纸的编号不能和信封的编号一样,全都不能一样. 思路:错排公式. D(n)表示n件信封装错的所有的情况. ...

  10. 错排公式 全排列函数 next_permitation(a,a+n)

    不容易系列之一 错排:3件东西分别装进3个不同的特定的袋子,如果刚好一个都没有装对,就叫做错排! 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 做好“一件”事情尚且不易,若想永远 ...

随机推荐

  1. 洛谷P1118数字三角形,

    #include <bits/stdc++.h> using namespace std; int c[13][13];//杨辉三角 int b[13];//用于排除 int a[13]; ...

  2. NET Core 部署IIS 碰到得问题解决(内托管模式超时、不允许得请求谓词、直接请求无响应、拒绝服务405)

    web.config 配置说明 典型的web.confg 配置. 注意其中hostingModel模式和requestTimeout 进程内托管需要注意使用单独的应用程序池: 请求超时默认5分钟,出错 ...

  3. Vue的Component name报错

    问题描述: Component name "xxxxx" should always be multi-word.eslintvue 解决方案: 在项目目录中找到 .eslintr ...

  4. golang学习路线

    一.golang基础 李文周的博客:https://www.liwenzhou.com/ 视频教程:https://link.juejin.cn/?target=https%3A%2F%2Fwww.b ...

  5. CC协议的诞生背景

    CC协议的诞生背景 在当今世界绝大部分国家的法律法规中,作品的版权一般都保留于创造者或拥有人手中,在没有特殊声明的情况下,任何人想要获取或使用该作品,都要事先取得版权所有者的授权,才可以进行合法的获取 ...

  6. python之pyqt5-第一个pyqt5程序-图像压缩工具(2.5版本,加入多线程进度条与文件drop)-小记

    (如想转载,请联系博主或贴上本博地址) 题外:关于python的多线程 python因为GIL的原因,只能利用到单核CPU性能.如程序内多是计算或循环,多线程无啥意义:如程序内多IO操作,多线程可以避 ...

  7. Keil 报错解决方法:Cannot link object xxx.o as its attributes are incompatile with the image attributes

    链接其他人的lib库时报错:Cannot link object xxx.o as its attributes are incompatile with the image attributes 解 ...

  8. python abseil库(app, flags, logging)总结

    absl (Abseil PythonCommon Libraries)(https://abseil.io/docs/python/)是用于构建Python应用程序的Python库代码集合,它包括三 ...

  9. 基于TDesign风格的Blazor企业级UI组件库

    作为一名Web开发人员,开发前端少不了使用JavaScript,而Blazor就是微软推出的基于.net平台交互式客户 Web UI 框架,可以使用C#替代JavaScript,减少我们的技术栈.降低 ...

  10. Spring------bean基础配置

    Bean基础配置 Bean的别名配置: 在执勤已经定义好id的基础上,如果对该名称并不是很满意,但是又不是很想要去修改许多又利用到它的地方,可以选择在ApplicationContext.xml中配置 ...