CF104E New Year Garland

粘个题解。。。

100% 先考虑小问题:恰用 j 种颜色布置一行 i 个球的方案数 dp[i][j]。
用类似于最小表示法的思想,我们要求 x 号颜色的首次出现位置必须比 x+1
号颜色的早,这样一来将所求得的方案数乘以颜色的全排列数 j!就是原来的
方案数。若前 i-1 个球使用了 j-1 种颜色,则第 i 个球必然使用了第 j 种颜色;
若前 i-1 个球已使用了 j 种颜色,则第 i 个球使用的颜色必须与第 i-1 个球不
同,所以 有(j-1)种方案。故可由简单的 dp 递推而得:
F[i][j] = F[i-1][j-1] + F[i-1][j] * (j-1)
现在考虑相邻两层之间的限制,用 d[i][j]表示前 i 层中第 i 层恰用了 j 种颜色
的方案数。因为使用的颜色数不可能多于球数,又总球数不超过10^7,故d[i][j]
的状态总数也不超过 10^7。
若不考虑两层之间的颜色集合需不同这一条件,则转移方程为
d[i][j] = (m!/(m-j)!) * F[l[i]][j] * Σd[i-1][k]
再减去不符合这一条件的部分即可:
d[i][j] = (m!/(m-j)!) * F[l[i]][j] * Σd[i-1][k] – d[i-1][j] * F[l[i]][j] * j!
其中(m!/(m-j)!)与 j!都可以预处理得到
时间复杂度:O(Σl[i] + l[i]^2)

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 int n,m,p,cnt,tot,mx;
 6 long long sum,tmp,ml;
 7 int l[1000005];
 8 long long mul[1000005];
 9 long long f[5005][5005];
10 long long pr[1000005];
11 long long dp[1000005];
12 void pre_work(){
13     mul[m+1]=1ll;
14     for(int i=m;i>=1;i--)
15         mul[i]=mul[i+1]*1ll*i%p;
16 }
17 int main(){
18     scanf("%d%d%d",&n,&m,&p);
19     pre_work();
20     for(int i=1;i<=n;i++){
21         scanf("%d",&l[i]);
22         mx=max(l[i],mx);
23     }f[0][0]=1;
24     for(int i=1;i<=mx;i++)
25         for(int j=1;j<=min(i,m);j++)
26             f[i][j]=(f[i-1][j-1]+f[i-1][j]*1ll*(j-1))%p;
27     tmp=1;
28     for(int i=1;i<=n;i++){
29         sum=tmp;tmp=0;ml=1;
30         for(int j=1;j<=l[i];j++){
31             ml*=1ll*j;ml%=p;
32             dp[j]=((sum*mul[m-j+1]%p*f[l[i]][j]%p-pr[j]*f[l[i]][j]%p*ml%p)%p+p)%p;
33             (tmp+=dp[j])%=p;
34         }
35         for(int j=1;j<=l[i-1];j++)pr[j]=0;
36         for(int j=1;j<=l[i];j++)pr[j]=dp[j];
37     }printf("%I64d\n",tmp);
38     return 0;
39 }

 

转载于:https://www.cnblogs.com/lnxcj/p/10356583.html

你可能感兴趣的:(CF104E New Year Garland)