省選專練SDOI2016排列計數
阿新 • • 發佈:2019-02-20
引證:錯排遞推式:
f(n)=(f(n-1)+f(n-2))*(n-1)
試證:
f表示當前n個的錯排。
當前選擇n時,第一,對於位置k,互換則權值加上f(n-2)個錯排,否則加上f(n-1)個錯排。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; #define ll long long inline void read(int &x){ x=0; int f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-'){ f=-1; } ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } x*=f; } const ll mod=1e9+7; const ll N=1e6+10; ll fac[N]={0}; ll f[N]={0}; ll quick_pow(ll sum,int x){ ll temp=1; while(x){ if(x%2==1){ temp=temp*sum%mod; } sum=sum*sum%mod; x/=2; } return temp; } ll inv(ll x){ return quick_pow(x,mod-2); } ll C(ll n,ll m){ ll x=fac[n]; ll y=fac[m]*fac[n-m]%mod; y=inv(y); return x*y%mod; } int main(){ f[0]=1; f[1]=0; for(int i=2;i<=1000010;i++){ f[i]=(i-1)*(f[i-1]+f[i-2])%mod; } fac[0]=1; for(int i=1;i<=1000010;i++){ fac[i]=fac[i-1]*i%mod; } int T; read(T); // scanf("%d",&T); while(T--){ int n,m; read(n); read(m); // scanf("%d%d",&n,&m); printf("%lld\n",C(n,m)*f[n-m]%mod); } }