题目链接:
https://www.codechef.com/problems/LEMOVIE
对于这种类似排列,并且有大小关系的贡献,一般要按从大到小或从小到大插入进行讨论
一组数有贡献当且仅当至少一个数被插到了最前面,那么就分情况进行讨论即可
就是插板法,把y个数插到x个数当中,把x个数之间的空隙看成盒子
因为是排列,所以插完以后还要乘一下阶乘
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<stack> #include<cmath> using namespace std; typedef long long ll; const int maxn = 210; const int mod = 1e9+7; int T,n,m,q; int a[maxn],b[maxn],c[maxn]; int f[maxn][maxn]; int C[1010][1010],jc[1010]; bool cmp(int a,int b){ return a>b; } ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f;} int main(){ T=read(); jc[0]=1; for(int i=1;i<=1000;i++) jc[i]=1ll*jc[i-1]*i%mod; C[0][0]=1; for(int i=1;i<=1000;i++){ C[i][0]=C[i][i]=1; for(int j=1;j<i;j++){ C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } while(T--){ q=0; memset(f,0,sizeof(f)); n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++){ if(a[i]!=a[i-1]){ b[++q]=a[i]; c[q]=1; }else{ ++c[q]; } } f[0][0]=1; int cnt=0; for(int i=1;i<=q;i++){ for(int j=1;j<=m;j++){ f[i][j]=(1ll*f[i-1][j]*jc[c[i]]%mod*C[c[i]+cnt-1][cnt-1]%mod+1ll*f[i-1][j-1]*jc[c[i]]%mod*C[c[i]+cnt-1][cnt]%mod)%mod; } cnt+=c[i]; } int ans=0; for(int i=1;i<=m;i++) ans=(ans+f[q][i])%mod; printf("%d\n",ans); } return 0; }