码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 140E.New Year Garland

时间:2019-02-08 23:30:14      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:ret   and   clu   答案   long   二维   memset   维数   com   

传送门:

解题思路:

要求相邻两行小球颜色集合不同,并且限制行内小球相邻不同。

由此可得:每行小球排列都是独立与外界的,

所以答案应该是对于所有行的颜色集合分类,在将行内的答案乘到上面。

先考虑如何分类:

我们可以确定对于每行所取的颜色种类$x=|S|$,

若相邻两行$i,j$,其$x_i!=x_j$,那么一定是合法的,有$C_m^x$种选择方法。

而对于相邻两行$x_i=x_j$,对于行$i$的一种方案,只有一种可能使得$S_i=S_j$,

所以可以使用容斥来计算答案

综上所述,按照每行的颜色种类数来分类或许是可行的。

所以说我们表示出答案:

设该行共用$x$种颜色的方案数为$f(x)$,$f(x)$是对于所有的种类进行计数的,所以可以直接与颜色数为$x$的其他计数变量相乘,设第$n$行中颜色为$i$对整体的贡献为$ans_{n,i}$则:

$ans_n=C_m^x*f(x)*ans_{n-1}-f(x)*ans_{n-1,j}$

$ans_n=\sum\limits_{c=1}^{l_n}ans_{n,c}$

用函数$g_{i,j}$表示就是$ans_i=\sum g_{i,j}$表示前$i$行中最后一行用$j$个颜色方案数。

行间计数搞定了,就该考虑如何计算$f(x)$
由于刚才设$f(x)$为该行的方案数。这个看起来不太好求。

考虑什么决定了这个方案数。

是该行的球数以及颜色数。

所以不妨改写一下,$f(i,j)$表示用了$i$个球,共$j$种颜色的方案数,那么第$i$行的$f(x)$重写为$f(l_i,x)$

考虑一个一个来添加球,由于要求和前一个颜色不同,即可获得递推式:

$f(i,j)=f(i-1,j-1)+f(i-1,j)*(j-1)$

由于每次用到没有用过的颜色顺序是有序的,而所求的是对球颜色顺序无要求,那么最后使用的时候应写成:
$j!*f(i,j)$

球颜色数不会多于总数,那么$f(i,j)$,可以用二维数组来储存


最后一个问题就是p不是质数不能直接用逆元。

难不成要用拓展Lucas?

组合数可以提出来:

那么答案就是:

$g_{i,j}=A_{m}{j}*f(i,j)*\sum{g_{i-1}}-j!*f(i,j)*g_{i-1,j}$

其中$f_{(i,j)},j!,A_m^j$预处理就可以很愉快地A掉这道题目了

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long lnt;
 5 lnt n,m,p;
 6 lnt lmax;
 7 lnt Am[50001];
 8 lnt fac[50001];
 9 lnt l[2000000];
10 lnt f[5010][5010];
11 lnt g[2][5010];
12 int main()
13 {
14     scanf("%lld%lld%lld",&n,&m,&p);
15     fac[0]=Am[0]=f[0][0]=1;
16     for(int i=1;i<=n;i++)
17         scanf("%lld",&l[i]),lmax=std::max(lmax,l[i]);
18     for(int i=1;i<=lmax;i++)Am[i]=Am[i-1]*(m-i+1)%p;
19     for(int i=1;i<=lmax;i++)fac[i]=fac[i-1]*i%p;
20     for(int i=1;i<=lmax;i++)for(int j=1;j<=i&&j<=m;j++)
21         f[i][j]=(f[i-1][j-1]+f[i-1][j]*(j-1))%p;
22     lnt ans=1,sum=0;
23     for(int i=1;i<=n;i++)
24     {
25         for(int j=1;j<=l[i];j++)
26         {
27             lnt tmp=(Am[j]*ans-g[i&1^1][j]*fac[j])%p;
28             g[i&1][j]=f[l[i]][j]*tmp%p;
29             sum+=g[i&1][j];
30         }
31         ans=(sum%p+p)%p;
32         sum=0;
33         memset(g[i&1^1],0,sizeof(g[0]));
34     }
35     printf("%lld\n",ans);
36     return 0;
37 }

codeforces 140E.New Year Garland

标签:ret   and   clu   答案   long   二维   memset   维数   com   

原文地址:https://www.cnblogs.com/blog-Dr-J/p/10356883.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!