用$m$种颜色的彩球装点$n$层的圣诞树。圣诞树的第$i$层恰由$a_{i}$个彩球串成一行,且同一层内的相邻彩球颜色不同,同时相邻两层所使用彩球的颜色集合不 同。求有多少种装点方案,答案对$p$取模。

好神的计数问题,zwz Orz

题解思路来自黄学长hzwer的博客

先只考虑在一行内的彩球的方案数

定义$g[i][j]$表示一共有$i$个球串成一行,一共用了$j$种颜色的方案数

因为所有颜色都是等价的,我们可以利用最小表示法来简化计数,比如让颜色编号为$x+1$的球第一次出现的位置,在颜色编号为$x$的球之前。实际的方案数是$g[i][j]\cdot j!$

这样递推关系就简单多了

加入一个新颜色的球,$g[i][j]+=g[i-1][j-1]$

加入一个旧颜色的球,颜色不能和第$i-1$个球相同,$g[i][j]+=(j-1)g[i-1][j]$

$g[i][j]=g[i-1][j-1]+(j-1)g[i-1][j]$

在考虑行行之间的影响

定义$f[i][j]$表示前$i$行,其中第$i$行选了$j$种颜色的方案数

如果没有相邻两行集合不同这种限制

$f[i][j]=C_{m}^{j}\cdot g[a_{i}][j]\cdot \sum f[i-1][k]$

如果加上限制,

$f[i][j]=C_{m}^{j}\cdot g[a_{i}][j]\cdot j!\sum f[i-1][k]-g[a_{i}][j]\cdot j!\cdot f[i-1][j]$

$=A_{m}^{j}\cdot g[a_{i}][j]\sum f[i-1][k]-g[a_{i}][j]\cdot j!\cdot f[i-1][j]$

利用前缀和优化可以$O(1)$转移

$f[i][j]$的状态数也仅仅是$O(\sum a_{i})$,用滚动数组记录

$A_{m}^{j}$和$j!$可以通过预处理得到

总结:由于本题的模数是非质数,用组合数计数会让问题变得复杂,且时间复杂度很难保证。如果本题保证模数为质数,可能会有很多其他做法,比如组合数+容斥等等,但应该都没有官方题解的思路简洁。出题者似乎引导我们走向突破口——消去组合数,突破口在于通过化简,把组合数化成排列数和阶乘,排列数和阶乘即使在模数为非质数的情况下,也能在$O(n)$时间预处理

 #include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 5010
#define M1 1000010
#define dd double
#define ll long long
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m,mx,P; int f[][N1],g[N1][N1],am[N1],mul[N1],a[M1]; int main()
{
int i,j,x;
scanf("%d%d%d",&n,&m,&x);
for(i=;i<=n;i++) scanf("%d",&a[i]), mx=max(mx,a[i]);
const int p=x;
g[][]=g[][]=;
for(i=;i<=mx;i++) for(j=;j<=i;j++) g[i][j]=(1ll*(j-)*g[i-][j]%p+g[i-][j-])%p;
mul[]=mul[]=; am[]=;
for(i=;i<=min(m,mx);i++) am[i]=1ll*am[i-]*(m-i+)%p;
for(i=;i<=mx;i++) mul[i]=1ll*mul[i-]*i%p;
int now=,pst=,snow=,spst=;
f[pst][]=;
for(i=;i<=n;i++)
{
snow=;
for(j=;j<=min(m,a[i]);j++)
f[now][j]=(1ll*am[j]*g[a[i]][j]%p*spst%p-1ll*f[pst][j]*mul[j]%p*g[a[i]][j]%p+p)%p, (snow+=f[now][j])%=p;
memset(f[pst],,(min(m,a[i-])+)<<);
swap(now,pst); swap(snow,spst);
}
printf("%d\n",spst);
return ;
}

CF140E New Year Garland (计数问题)的更多相关文章

  1. [cf140e]New Year Garland

    Description 用$m$种颜色的彩球装点$n$层的圣诞树.圣诞树的第$i$层恰由$l[i]$个彩球串成一行,且同一层内的相邻彩球颜色不同,同时相邻两层所使用彩球的颜色集合不同. 求有多少种装点 ...

  2. 一些gcd计数问题

    数论什么的全都忘光了吧QAQ 做了几道简单的题练习一下. bzoj1101: [POI2007]Zap 求有多少对数满足 gcd(x,y)=d, 1<=x<=a, 1<=y<= ...

  3. POJ 1759 Garland(二分+数学递归+坑精度)

    POJ 1759 Garland  这个题wa了27次,忘了用一个数来储存f[n-1],每次由于二分都会改变f[n-1]的值,得到的有的值不精确,直接输出f[n-1]肯定有问题. 这个题用c++交可以 ...

  4. poj 1759 Garland (二分搜索之其他)

    Description The New Year garland consists of N lamps attached to a common wire that hangs down on th ...

  5. 扩展Python模块系列(四)----引用计数问题的处理

    承接上文,发现在使用Python C/C++ API扩展Python模块时,总要在各种各样的地方考虑到引用计数问题,稍不留神可能会导致扩展的模块存在内存泄漏.引用计数问题是C语言扩展Python模块最 ...

  6. poj 1759 Garland

    Garland Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 2365   Accepted: 1007 Descripti ...

  7. 置换群、Burnside引理与等价类计数问题

    置换群.Burnside引理与等价类计数问题 标签: 置换群 Burnside引理 置换 说说我对置换的理解,其实就是把一个排列变成另外一个排列.简单来说就是一一映射.而置换群就是置换的集合. 比如\ ...

  8. C. Nice Garland Codeforces Round #535 (Div. 3) 思维题

    C. Nice Garland time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...

  9. D. Diverse Garland Codeforces Round #535 (Div. 3) 暴力枚举+贪心

    D. Diverse Garland time limit per test 1 second memory limit per test 256 megabytes input standard i ...

随机推荐

  1. System v和posix的IPC对比

    之前有一篇关于共享内存的System V和Posix的对比: http://www.cnblogs.com/charlesblc/p/6261469.html POSIX(Portable Opera ...

  2. JAVAEE之-----MySQL分页技术(带搜索)

    需求: 为什么须要採用分页技术呢?在数据库中我们查询数据的时候,须要将数据返回到显示页面.数据库中含有大量数据,所有显示在一个页面过于太多,所以我们须要採用分页技术.每一页显示不同数据. 主要解决这个 ...

  3. Android:ExpandableListView使用

    前言 眼下回到了工作岗位,第一件事情就是ExpandListView的优化.这里简单的用一个Demo介绍一下ExpandableListView的使用. 简介一下Demo实现的功能,主要是继承Base ...

  4. Android最佳实践之性能 - 多线程

    在单独线程执行代码 參考地址:http://developer.android.com/training/multiple-threads/define-runnable.html Runnable对 ...

  5. DRP——重定向与转发

    重定向 重定向就是又一次进行请求.第一次请求.容器推断请求的类型,是否须要重定向. 重定向的语句是"response.SendRedirect("index.jsp"); ...

  6. 使用RabbitMQ放置自己定义对象(不借助序列化工具,比如protobuffer)V2.0

    怎样使用RabbitMQ盛放自己定义的对象呢?一般都会使用序列化工具在投放之前转换一次.从MQ取回的时候再逆序列化还原为本地对象.这里使用C++自带的强制类型装换,将本地对象的内存模型当做自然的序列化 ...

  7. QString够绕的,分为存储(编译器)和解码(运行期),还有VS编译器的自作主张,还有QT5的变化

    多读几篇,每篇取几句精华加深我对QString的理解. ------------------------------------------------------------------ QStri ...

  8. 如何提升SQL语句的查询性能

    在对数据库进行操作时,如果SQL语句书写不当,对程序的效率会造成很大影响. 提高SQL效率可以从一下几个方面入手: 1,数据库设计与规划 Primary Key字段的长度尽量小,能用small int ...

  9. 使用Azure Docker容器注册表服务

    1.登录你的Azure 容器注册表服务 az acr login --name ledesign 2.给你本地准备好的Image打上上云之前的版本标签 docker tag ledesign-serv ...

  10. guice基本使用,三种注入方式(二)

    guice提供了强大的注入方式. 1.属性注入 2.构造器注入 3.set方式注入 1.属性注入: package com.ming.user.test; import com.google.inje ...