题目大意

  定义一个序列的权值为:把所有相邻的相同的数合并为一个集合后,所有集合的大小的乘积。

  特别的,第一个数和最后一个数是相邻的。

  现在你有 \(n\) 种数,第 \(i\) 种有 \(c_i\) 个。求所有不同的序列的权值的和。

  \(n\leq 50,c_i\leq 100\)

题解

  考虑第一个数和最后一个数不相邻时怎么做。

  记 \(g_{i,j}\) 为出现了 \(i\) 次的数分成 \(j\) 个集合,所有集合大小的乘积的和。

\[g_{i,j}=\sum_{k=1}^ig_{i-k,j-1}\times k
\]

  假设最后 \(i\) 分成了 \(a_i\) 个集合,那么答案就是 \(\prod_{i=1}^ng_{c_i,a_i}\) 再乘上方案数。

  方案数可以容斥求。

  具体来说,把最后相邻且同色的球合并成一个大球。设最后有 \(b_i\) 个大球,那么容斥系数就是 \({(-1)}^{a_i-b_i}\),带容斥系数的方案数就是 \(\binom{a_i-1}{b_i-1}{(-1)}^{a_i-b_i}\)

  最后这 \(\sum b_i\) 个球可以随意放,方案数是 \(\frac{(\sum b_i)!}{\prod b_i!}\)

  总的答案是

\[\left(\prod_{i=1}^ng_{c_i,a_i}\binom{a_i-1}{b_i-1}{(-1)}^{a_i-b_i}\right)\frac{(\sum_{i=1}^nb_i)!}{\prod_{i=1}^n b_i!}
\]

  这样就可以 DP 了。(状态为 \(i\) 和 \(\sum b_i\))

  考虑第一个数和最后一个数相邻时怎么做。

  可以用最小表示法,令第一个数为 \(1\) 且 最后一个数不为 \(1\)(除非 \(n=1\))。

  只需要在后面计算组合数的时候把 \(b_1-1\) 再除以 \(a_1\) 就可以得到第一个数为 \(1\) 的方案数。

  把 \(b_1-2\) 再除以 \(a_1\) 就可以得到第一个数为 \(1\) 且最后一个数也是 \(1\) 的方案数。

  除以 \(a_1\) 是因为一个方案会被算多次。

  再把方案数乘以 \(\sum c_i\) 就是答案了。

  时间复杂度:\(O((\sum c_i)^2)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll p=1000000007;
ll fac[5010],ifac[5010],inv[5010];
ll f[60][5010];
ll g[110][110];
int a[60];
int n;
int s[60];
ll c[110][110];
ll c1[110],c2[110];
ll binom(int x,int y)
{
return x>=y&&y>=0?fac[x]*ifac[y]%p*ifac[x-y]%p:0;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(int i=2;i<=5000;i++)
{
inv[i]=-p/i*inv[p%i]%p;
fac[i]=fac[i-1]*i%p;
ifac[i]=ifac[i-1]*inv[i]%p;
}
g[0][0]=1;
for(int i=1;i<=100;i++)
for(int j=1;j<=100;j++)
for(int k=1;k<=i;k++)
g[i][j]=(g[i][j]+g[i-k][j-1]*k)%p;
f[0][0]=1;
for(int i=1;i<n;i++)
for(int j=1;j<=a[i];j++)
for(int k=1;k<=j;k++)
c[i][k]=(c[i][k]+g[a[i]][j]*binom(j-1,k-1)%p*((j-k)&1?-1:1))%p;
for(int i=n;i<=n;i++)
for(int j=1;j<=a[i];j++)
for(int k=1;k<=j;k++)
c1[k]=(c1[k]+g[a[i]][j]*binom(j-1,k-1)%p*((j-k)&1?-1:1)*inv[j])%p;
for(int i=1;i<=n;i++)
for(int j=1;j<=a[i];j++)
for(int k=0;k<=s[i-1];k++)
f[i][k+j]=(f[i][k+j]+f[i-1][k]*c[i][j]%p*binom(k+j,k))%p;
ll ans=0;
for(int j=1;j<=a[n];j++)
for(int k=0;k<=s[n-1];k++)
ans=(ans+f[n-1][k]*c1[j]%p*(binom(k+j-1,k)-binom(k+j-2,k)))%p;
ans=ans*s[n]%p;
ans=(ans+p)%p;
printf("%lld\n",ans);
return 0;
}

【XSY3156】简单计数II 容斥 DP的更多相关文章

  1. 【BZOJ2839】集合计数(容斥,动态规划)

    [BZOJ2839]集合计数(容斥,动态规划) 题面 BZOJ 权限题 Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使 ...

  2. [CF1086E]Beautiful Matrix(容斥+DP+树状数组)

    给一个n*n的矩阵,保证:(1)每行都是一个排列 (2)每行每个位置和上一行对应位置不同.求这个矩阵在所有合法矩阵中字典序排第几.考虑类似数位DP的做法,枚举第几行开始不卡限制,那么显然之前的行都和题 ...

  3. $bzoj2560$ 串珠子 容斥+$dp$

    正解:容斥+$dp$ 解题报告: 传送门$QwQ$ $umm$虽然题目蛮简练的了但还是有点难理解,,,我再抽象一点儿,就说有$n$个点,点$i$和点$j$之间有$a_{i,j}$条无向边可以连,问有多 ...

  4. 知识点简单总结——minmax容斥

    知识点简单总结--minmax容斥 minmax容斥 好像也有个叫法叫最值反演? 就是这样的一个柿子: \[max(S) = \sum\limits_{ T \subseteq S } min(T) ...

  5. HDU 5794 A Simple Chess (容斥+DP+Lucas)

    A Simple Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 Description There is a n×m board ...

  6. 【BZOJ3622】已经没有什么好害怕的了 容斥+DP

    [BZOJ3622]已经没有什么好害怕的了 Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output ...

  7. bzoj3782上学路线(Lucas+CRT+容斥DP+组合计数)

    传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3782 有部分分的传送门:https://www.luogu.org/problemnew/ ...

  8. [HAOI2017]方案数[组合计数、容斥、dp]

    题意 题目链接 分析 先考虑没有障碍怎么做,定义 f(i,j,k) 每一维走了 i,j,k 位的方案数,转移乘个组合数即可. 现在多了一些障碍,考虑容斥.实际我们走过的点都有严格的大小关系,所以先把所 ...

  9. bzoj2839 集合计数(容斥)

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 883  Solved: 490[Submit][Status][Discuss] ...

随机推荐

  1. Django 如何获取真实远程客户端IP

    问题简述 我们知道HttpRequest.META字典包含所有HTTP头部信息(可用的头部信息取决于客户端和服务器).一般情况下,HttpRequest.META.get('REMOTE_ADDR') ...

  2. 如何用git上传代码到github详细步骤

    注册账户 这个小菜鸟带着心跳写的第一篇博客! 还请大家多多提点! 想使用github,第一步肯定是要注册github账号,有了账号就是直接登录啦 可以直接打开http://github.com页面注册 ...

  3. mssql sqlserver 快速表备份和表还原的方法

    摘要: 在sqlserver维护中,我们偶尔需要运行一些sql脚本对数据进行相关修改操作,在数据修改前我们必须对表数据进行备份来避免出现异常时,可以快速修复数据, 下文讲述sqlserver维护中,快 ...

  4. SQL 使用临时表和临时变量完成update表字段---实际案例

    -- 使用临时表 -- 创建临时表 --ALTER TABLE TS_ExpenseApplication_Reim_Detail ADD BgCode NVARCHAR() NULL, BgItem ...

  5. 利用ZYNQ SOC快速打开算法验证通路(1)——MATLAB浮点数与定点二进制补码互转

    最近本人一直在学习ZYNQ SOC的使用,目的是应对科研需要,做出通用的算法验证平台.大概思想是:ZYNQ PS端负责与MATLAB等上位机数据分析与可视化软件交互:既可传输数据,也能通过上位机配置更 ...

  6. maven常用仓库

    ==================2014-04-19添加========可访问=============================== http://nexus.openkoala.org/ ...

  7. Linux(Centos7)下搭建SVN服务器 (转载)

    系统环境:centos7.2 第一步:通过yum命令安装svnserve,命令如下: yum -y install subversion 此命令会全自动安装svn服务器相关服务和依赖,安装完成会自动停 ...

  8. python3 shell 中添加清屏

    在windows中: 安装目录 \Lib(  D:\Python37\Lib) 中添加 ClearWindow.py 文件,文件内容: """ Clear Window ...

  9. 新数据革命: 开源C#图形化爬虫引擎Hawk5发布

    https://ferventdesert.github.io/Hawk/ Hawk是一款由沙漠之鹰历时五年个人业余时间开发的,开源图形化爬虫和数据清洗工具,GitHub Star超过2k+,前几代版 ...

  10. Linux-基础学习(三)-Nginx学习

    1.nginx安装与部署 1.1 nginx入门 Web 网络服务是一种被动访问的服务程序,即只有接收到互联网中其他主机发出的 请求后才会响应,最终用于提供服务程序的 Web 服务器会通过 HTTP( ...