【SDOI 2016】 排列计数
2024-09-30 19:55:34
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4517
【算法】
有m个数在原来的位置上,说明有(n-m)个数不再原来的位置上
那么,我们可以选出(n-m)个数,使这(n-m)个数都不在原来的位置上,再让剩下的m个数都在原来的位置上
错位排列递推公式 :
f(1) = 0
f(2) = 1
f(n) = (n - 1)(f(n-1) + f(n-2)) (n >= 2)
因此,答案为C(n,n-m)f(n-m)
预处理错位排列数,阶乘和阶乘逆元,即可
【代码】
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000010
const int P = 1e9 + ; int T,n,m,ans;
int f[MAXN],fac[MAXN],inv[MAXN]; inline int power(int a,int n)
{
int res = ,b = a;
while (n)
{
if (n & ) res = 1ll * res * b % P;
b = 1ll * b * b % P;
n >>= ;
}
return res;
}
inline void init()
{
int i;
f[] = ;
f[] = ;
f[] = ;
for (i = ; i < MAXN; i++) f[i] = 1ll * (i - ) * (f[i-] + f[i-]) % P;
fac[] = ;
for (i = ; i < MAXN; i++) fac[i] = 1ll * fac[i-] * i % P;
inv[MAXN-] = power(fac[MAXN-],P-);
for (i = MAXN - ; i >= ; i--) inv[i] = 1ll * inv[i+] * (i + ) % P;
}
inline int C(int n,int m)
{
if (n < m) return ;
if (m == ) return ;
return 1ll * fac[n] * inv[m] % P * inv[n-m] % P;
} int main()
{ init();
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
ans = 1ll * C(n,n-m) * f[n-m] % P;
printf("%d\n",ans);
} return }
最新文章
- 免费开源分布式系统日志收集框架 Exceptionless
- jenkins添加git源码目录时报Error performing command错误
- PL/SQL创建数据表空间
- C#的泛型委托Predicate/Func/Action(转)
- EF——Guid类型数据的自增长、时间戳和复杂类型的用法 03 (转)
- StringReplace用法
- E-BOM和M-BOM的区别
- Eclipse热部署JSP
- Ubuntu下GCC的安装以及版本控制
- 【grunt整合版】 30分钟学会使用grunt打包前端代码
- codeforces 645C . Enduring Exodus 三分
- gallery 从最左边开始显示并且默认选中第一个
- #417 Div2 C
- 201521123006 《Java程序设计》第1周学习总结
- 自己做一台3D打印机到底有多难?(附教程)
- get请求乱码解决
- 后Hadoop时代的大数据技术思考:数据即服务
- CSS中常见的长度单位
- 1.3 C++引用(Reference)
- BASIC-11_蓝桥杯_十六进制转十进制