4517: [Sdoi2016]排列计数
思路:
首先,要确定定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 }