题目地址 : http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=12886
由于不擅长DP。对于这题。
比赛的时候根本没去想。直接pass掉。。。 赛后才发现这题不难。
很容易就能推算出不重复的摆法总数是 n! / (n-m)! *((n-m)^(p-m))
然后用记忆化DFS,逐层往前,把重复的剪掉即可。
#include<iostream> #include<cstring> #define ll long long using namespace std; const int mod=1000000007; ll c[1300][1300],all[3000],self[3000]; ll cal(int n,int m,int p){ if(n<=m && m<p) return 0; ll res=1; for(int i=0;i<p;i++) if(i<=m) res=res*(n-i)%mod; else res=res*(n-m)%mod; return res; } void init_(){ int i,j; c[0][0]=1; for(i=1;i<=1100;i++){ c[i][0]=1; for(j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } void init_(int n,int m,int p){ for(int i=0;i<=n;i++) all[i]=cal(i,m,p); memset(self,-1,sizeof(self)); } ll f(int n,int m,int p){ if(self[n]!=-1) return self[n]; self[n]=all[n]; for(int i=n-1;i>0;i--) self[n]=(self[n]-c[n][i]*f(i,m,p))%mod+mod; return self[n]%=mod; } int main(){ int n,m,p; ll res; init_(); while(cin>>n>>m>>p){ init_(n,m,p); if(p<n) res=0; else res=f(n,m,p); cout<<res<<endl; } return 0; }