P4071 [SDOI2016]排列计数
P4071
题意:
给出一个序列,然后\(A[i]\)的位置放i则称这是稳定的,然后剩下的\(n-m\)种则是不稳定的,
思路:
稳定的那\(m\)个数就是在\(n\)个数中选择\(m\)个数让他稳定,
然后剩下的不稳定的就是\(n-m\)个数做错排的方案数,
啥是错排:
这就是一个错排的板子题,然后我们按照这个板子题来讲错排的原理,
就是\(n\)封信,装到\(n\)个信封中,都装错了.
我们先看第一个人,因为第一个人装错的话有\(n-1\)种情况,就长这样:
然后拿出其中的一种来看,如果第二封信选择了第一个信封那就是后边的\(n-2\)个数做错排:
如果第二个没有选第一封信,那就相当于对剩下的\(n-1\)个做错排.
我们就很容易得到一个递推式(设\(f[i]\) 为给i个数做错排的方案数):
\[(n - 1) \ast (f[n - 1] + f[n - 2])\]
边界条件就是\(n\)为\(1\)和\(2\)的时候,当\(n\)只有\(1\)的时候只能放到这个信封中,所以方案数为\(0\),
当\(n\)为\(2\)的时候只有下图这一种可能,所以方案数为\(1\).剩下的递推可得.
求组合数的话我们可以用\(Lucas\)定理来求得.
\(Lucas\)定理:
\[Lucas(n, m) \% mod = \tbinom{n \% mod}{m \% mod} * Lucas(n, m)\]
因为这个题中\(n,m\)太大了,我们可以用公式直接求,因为需要\(mod\)一个数,
然后因为公式为\(\frac {n!} {m!(n - m)!}\) 有除法,因为\(mod\)意义下没有除法运算,
然后我们可以求出\(m!(n - m)!\) 的逆元,让\(n!\) 乘以\(m!(n - m)!\) 的逆元来求\(mod\)意义下的组合数.
因为\(mod\)的这个数为质数,我们可以直接利用费马小定理来求逆元.
费马小定理;
\[a^{p - 1} \equiv 1 \ (mod \ p)\]
所以 \[a \ast a^{p -2} \equiv 1 \ (mod \ p)\]
所以在$mod p \(的情况下\)a\(的逆元就是\)a ^ {p - 2}$
做的时候我们可以先处理出前\(1000000\)的错排和阶乘.
code :
#include <bits/stdc++.h>
#define N 1000010
#define M 1010
#define ll long long
using namespace std;
ll mod = 1e9 + 7;
ll t, n, m, f[N], jc[N];
ll read() {
ll s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
ll q_pow(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1) ans = (ans * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ans;
}
ll c(ll a, ll b) {
return (jc[a] % mod * q_pow(jc[b] * jc[a - b] % mod, mod - 2) % mod) % mod;
}
ll lucas(ll a, ll b) {
if (!b) return 1;
else return (lucas(a / mod, b / mod) * c(a % mod, b % mod)) % mod;
}
int main() {
t = read();
f[1] = 0, f[2] = 1, jc[1] = 1, jc[2] = 2;
for (ll i = 3; i <= 1000000; i++)
f[i] = ((i - 1) * (f[i - 1] + f[i - 2]) % mod) % mod, jc[i] = (jc[i - 1] * i) % mod;
while (t--) {
n = read(), m = read();
if (n == m) puts("1");
else if (n - m == 1) printf("0\n");
else if (m == 0) printf("%lld\n",f[n]);
else {
ll ans = (f[n - m] % mod * lucas(n, m)) % mod;
printf("%lld\n", ans);
}
}
return 0;
}
原文地址:https://www.cnblogs.com/zzz-hhh/p/11736363.html
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(2)--云硬盘等后续配置
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(3)--为虚拟机指定固定ip
- ubuntu系统升级记录
- .NET Core系列 :4 测试
- 完整部署CentOS7.2+OpenStack+kvm 云平台环境(4)--用OZ工具制作openstack镜像
- centos下部署NTP时间服务器同步环境记录
- ASP.NET MVC扩展库
- centos7.2部署vnc服务记录
- nginx访问报错:Too many open files accept:
- iptables之NAT端口转发设置
- 使用Combres 库 ASP.NET 网站优化
- jQuery和asp.net mvc相关资源链接
- JavaScriptSerializer 序列化json 时间格式
- Nginx反向代理+负载均衡简单实现(https方式)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Pytorch学习之torch用法—-比较操作(Comparison Ops)
- PHP里的$_GET数组介绍
- PHP中$GLOBALS与global的区别详解
- MyBatis源码解析之基础模块—Log
- 启用OPCache提高PHP程序性能的方法
- 浅谈OpenCV中的新函数connectedComponentsWithStats用法
- Python根据指定文件生成XML的方法
- python如何调用java类
- Python pytesseract验证码识别库用法解析
- python 读txt文件,按‘,’分割每行数据操作
- PHP利用递归函数实现无限级分类的方法
- 详解关于php的xdebug配置(编辑器vscode)
- PHP应用跨时区功能的实现方法
- PHP实现的数据对象映射模式详解
- PDO::beginTransaction讲解