P4071 [SDOI2016]排列计数
题目大意:求的错位排序数
有全排列对于
我们称为错位排列
有递推式
证明:
设有的全排列
当时为0
当时为1
设最后1位为
有n在第位
- 若在上有 种错排
- 当不排在第位时,那么将第位重新考虑成一个新的“第位”,这时的包括在内的剩下个数的每一种错排,都等价于只有个数时的错排(只是其中的第位会换成第位)。其错排数为。
因为有种取法所以
#include <iostream>
using namespace std;
typedef long long ll;
ll f[25];
int main()
{
int n;
scanf("%d",&n);
f[1] = 0,f[2] = 1;
for(int i = 3 ; i <= n ; i ++ )
{
f[i] = (i - 1)*(f[i - 1] + f[i - 2]);
}
printf("%lld",f[n]);
}
然后我们就可写下面一道题了 [SDOI2016]排列计数
求有多少种 到 的排列 ,满足序列恰好有 个位置 ,使得 。
答案对 取模。
题目大意:
题意是让长度为n的序列有且仅有有m个数在原本的位置上.
也就是求除的错位排序数乘上个数的位置
通过预处理阶乘逆元和错位排序数,在进行查表操作即可
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1000010;
const int mod = 1e9 + 7;
ll db[N];
ll invfact[N],fact[N];
int power(int a,int b,int p)
{
int res = 1;
while(b)
{
if(b&1)res = (ll)res * a % p;
a = (ll) a * a % p;
b >>= 1;
}
return res;
}
void facts()
{
fact[0] = invfact[0] = 1;
for(int i = 1 ; i <= N ; i ++ )
{
fact[i] = (ll)fact[i - 1] * i % mod;
invfact[i] = (ll)invfact[i - 1] * power(i,mod - 2,mod) % mod;
}
}
void dbs()
{
db[1] = 0,db[2] = 1;
for(int i = 3 ; i <= N ; i ++ )
{
db[i] =(i - 1)*(db[i - 1] + db[ i - 2 ]) % mod;
}
}
int main()
{
int T,n,m;
scanf("%d",&T);
facts();
dbs();
while(T--)
{
scanf("%d%d",&n,&m);
if(n == m){printf("1\n");continue;}
ll cnm = (ll)fact[n] * invfact[m] % mod * invfact[n - m] % mod;
printf("%lld\n",(ll)cnm * db[n-m]%mod);
}
}
“风雪越是呼啸,雪莲越是绽放”
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?