4517: [Sdoi2016]排列计数

本文探讨了组合数学中错排问题的解决方法,并提供了一种高效的算法实现。通过确定特定位置上的元素,利用组合数C(n,m)计算可能的方案数,并结合错排公式求解剩余位置的排列方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

链接

思路:

  首先,要确定定m个位置,这些位置要求必须i=a[i],所以方案数是C(n,m),对于剩下的位置,要求i!=a[i],所以要求是一个错排。

错排公式

p[0] = 0,p[1] = 1

p[i] = (i-1)*(p[i-1]+p[i-2])

 

代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 
 7 using namespace std;
 8 
 9 const int mod = 1e9+7;
10 
11 int f[1000100],p[1000100];
12 
13 inline int read() {
14     int x = 0,f = 1;char ch=getchar();
15     for (; ch<'0'||ch>'9'; ch=getchar()) if(ch=='-')f=-1;
16     for (; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
17     return x*f;
18 }
19 
20 void init() {
21     f[0] = 1;
22     for (int i=1; i<=1000000; ++i) f[i] = (1ll * f[i-1] * i) % mod;
23     p[1] = 0;p[2] = 1;
24     for (int i=3; i<=1000000; ++i) p[i] = (1ll * (i-1) * (p[i-1] + p[i-2])) % mod;
25 }
26 
27 int inv(int a,int b) {
28     int ans = 1;
29     while (b) {
30         if (b & 1) ans = (1ll*ans*a) % mod;
31         a = (1ll * a * a) % mod;
32         b >>= 1;
33     }
34     return ans % mod;
35 }
36 
37 void solve(int n,int m) {
38     if (n == m) {cout << "1\n";return ;}
39     int t1 = inv(f[m],mod-2),t2 = inv(f[n-m],mod-2);
40     int ans = (1ll * f[n] * t1) % mod;
41     ans = (1ll * ans * t2) % mod;
42     ans = (1ll * ans * p[n-m]) % mod;
43     cout << ans << "\n";
44 }
45 
46 int main() {
47     int T = read();
48     init();
49     while (T--) {
50         int n = read(),m = read();
51         solve(n,m);
52     }
53     return 0;
54 }

 

转载于:https://www.cnblogs.com/mjtcn/p/8709801.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值