[dp][组合数] Jzoj P6303 演员

Description

 

题解

  • 设f[i][j][k]表示填完前i位,出现过j中颜色,后面还可以填k种颜色的方案数
  • 那么就会有两种转移:①填新的颜色f[i+1][j+1][k+1] ②填一种k中的颜色,填了这种颜色还能继续填f[i+1][j][k],不能继续填f[i+1][j][k-1]
  • 可以证明块最多只会有2m个,那就设[0/1]表示可以继续填的k种颜色中,最后一种是否出现在最后一位
  • 最后用组合数算算答案即可

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #define ll long long
 4 using namespace std;
 5 const ll N=310,M=1e6,mo=1e9+7;
 6 ll n,m,r,ans,fac[M*2],inv[M*2],f[N*2][N][N],g[N*2][N][N];
 7 ll ksm(ll a,ll b) { for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r; }
 8 ll C(ll a,ll b) { return fac[a]*inv[b]%mo*inv[a-b]%mo; }
 9 int main()
10 {
11     freopen("actor.in","r",stdin),freopen("actor.out","w",stdout),scanf("%lld%lld",&n,&m),fac[0]=1;
12     for (int i=1;i<=M;i++) fac[i]=fac[i-1]*i%mo;
13     inv[M]=ksm(fac[M],mo-2);
14     for (int i=M-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mo;
15     f[0][0][0]=1,ans=0;
16     for (int i=1;i<=min(2*m,n);i++) for (int j=1;j<=m;j++) for (int k=j,sum=0;k;k--)
17         f[i][j][k]=(f[i-1][j-1][k-1]+g[i-1][j][k+1])%mo,g[i][j][k]=(g[i][j][k+1]+f[i][j][k])%mo,ans=(ans+f[i][j][k]*C(m,j)%mo*fac[j]%mo*C(n-1,i-1)%mo)%mo;
18     printf("%lld",ans);
19 }

 

posted @ 2019-08-17 10:10  BEYang_Z  阅读(325)  评论(0编辑  收藏  举报