题解 P4071 【[SDOI2016]排列计数】
没思路?我们来找规律!
比如一个
共10种,很容易发现其实就是
没思路?我们再来找规律!
我们设
接着我们来看下
如果我们继续找下去的话,容易出错,所以我们现在来找找规律(灵魂画师)。
就拿
然后我们假设2放到1号位上去,剩下的3,4正好是
但2怎么可能只有放在1号位上的命运呢?它还可以不放到1号位,咦?我们之前说,i不能放到i号位,那么既然2不放到1号位,那么1号位在这里是不是等价于2号位呢?没错!
而之前的“万恶之源”数字1,它有
严谨的证明还请大家自己百度
然后我们就愉快地输出
其他知识点比如说逆元求组合数(费马小定理)还请大家自行了解
欢迎来我博客玩~
代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int MAXN=1000005,mod=1000000007;
ll f[MAXN],inv[MAXN],d[MAXN];
int t;
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=a*ans%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void prework(){
f[0]=1;
for(int i=1;i<MAXN;i++){
f[i]=f[i-1]*i%mod;
inv[i]=qpow(f[i],mod-2);
}
d[1]=0,d[2]=1,d[3]=2;
for(int i=4;i<MAXN;i++){
d[i]=(i-1)*(d[i-1]+d[i-2])%mod;
}
}
int main(){
cin>>t;
prework();
for(int i=1;i<=t;i++){
ll n,m;
scanf("%lld%lld",&n,&m);
if (n - m == 1) printf("0\n");
else if (m == n) printf("1\n");
else if (m == 0) printf("%lld\n",d[n]);
else {
printf("%lld\n",f[n] * inv[m] % mod * inv[n-m] % mod * d[n-m] % mod);
}
}
return 0;
}