【第二类斯特林数+容斥原理】Codeforces-140E. New Year Garland

题目链接(https://codeforces.com/problemset/problem/140/E)

E. New Year Garland

time limit per test 5 seconds

memory limit per test 256 megabytes

input standard input

output standard output

As Gerald, Alexander, Sergey and Gennady are already busy with the usual New Year chores, Edward hastily decorates the New Year Tree. And any decent New Year Tree must be decorated with a good garland. Edward has lamps of m colors and he wants to make a garland from them. That garland should represent a sequence whose length equals L. Edward's tree is n layers high and Edward plans to hang the garland so as to decorate the first layer with the first l1 lamps, the second layer — with the next l2 lamps and so on. The last n-th layer should be decorated with the last ln lamps, img

Edward adores all sorts of math puzzles, so he suddenly wondered: how many different ways to assemble the garland are there given that the both following two conditions are met:

  1. Any two lamps that follow consecutively in the same layer should have different colors.
  2. The sets of used colors in every two neighbouring layers must be different. We consider unordered sets (not multisets), where every color occurs no more than once. So the number of lamps of particular color does not matter.

Help Edward find the answer to this nagging problem or else he won't manage to decorate the Tree by New Year. You may consider that Edward has an unlimited number of lamps of each of m colors and it is not obligatory to use all m colors. The garlands are considered different if they differ in at least one position when represented as sequences. Calculate the answer modulo p.

Input

The first line contains three integers n, m and p (1n,m106,2p109) which are the number of the tree's layers, the number of the lamps' colors and module correspondingly. The next line contains n integers li (1 ≤ li ≤ 5000, img).

Output

Print the only integer — the number of garlands modulo p.

Examples

input

3 2 1000
3 1 2

output

8

input

2 3 1000
2 2

output

24

input

1 1 1000
5

output

0

Note

In the first sample the following variants are possible: 121|1|12, 121|1|21, 121|2|12, 121|2|21, 212|1|12, 212|1|21, 212|2|12, 212|2|21. In the second sample the following variants are possible: 12|13, 12|23, 12|31, 12|32 and so on.

Figure for the first sample:

img

题意

给一个n层能挂彩球的圣诞树(二维数组),每一层l[i]的大小固定,给定m种颜色,要求每一层的颜色集合不同,同一层相邻彩球颜色不同,问有多少种放法,结果对p取模

思路

一眼DP,但还是要一个个解决子问题

子问题一,先考虑第 i 层上能放多少种颜色,设f[i][j]表示长度为i的层放j种颜色的球的方案数:

这里的递推就是第二类斯特林数(懒得画图,语言来描述吧)

设某一层长度为n,颜色数为k

如果前n1个球只用了k1种颜色,那么最后一个球肯定要用剩下的那1种颜色,那么这部分的方案数就包含上一步只含k1种颜色的递推,f[l1][k1]1=f[l1][k1],

如果前n1个球已经用了k种颜色,那么最后一个球肯定要用与第l1个球不同的颜色,因为第l1个球可能有k种(都能涉及)颜色,第l个球只可能用与它不同的颜色,所以第l个球可能有(k1)种颜色,那么这部分的方案数就包含上一步含k种颜色的递推f[l1][k](k1),

f[i][j]=f[i1][j1]+f[i1][j](j1)

长度为l[i],那么最多用的颜色可以是l[i],预处理长度为l[i]的一层最多能用多少种方案数,可以累加,即设s[l[i]]=f[l[i]][1]Cm11!+f[l[i]][2]Cm22!+...+f[l[i]][l[i]]Cmii!,这里累加预处理的复杂度是O(i2)

子问题二,因为本层和上一层的颜色集合不能是一致的,可以开一个新的动态规划,用 dp[i][j]表示第i层用 j 种颜色的合法方案数(前提,第1i1层合法)

那么,它的转移方程式dp[i][j]=f[l[i]][j](s[i1]dp[i1][j]j!)

(翻译:这层本身方案数 * (上一层方案数 - 之前存在刚好和本层颜色方案相同的情况))

s[i]=j=1l[i]dp[i][j]Cmjj!,继续处理,Cmii!==mi_ ==mi1_(mi+1)(可以预处理)

预处理后,最后一种的方案数s[n]即为答案,复杂度O(l2+L)

AC代码

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
using namespace std;
typedef long long LL;
const int N = 5e3 + 1;
const int mod = 1e9 + 7;
const double pi = acos(-1.0);
int T, n, m, p;
int l[N];
int f[N][N];//子问题一
int fact[N], C[N];//阶乘,组合数
vector<int> gra[N];//学别人的,全图开一个vector优化空间
int s[N];
//取模前可能会爆int,如果没有define int ll的习惯取模前还是要加上ll
//思路讲的贼清楚,可以对应上,就不逐字符注释了
void solve() {
	for (int i = 1; i <= n; i++) {
		cin >> l[i];
		gra[i].resize(l[i] + 1);
	}//初始化

	f[0][0] = 1;
	for (int i = 1; i < N; i++) {
		for (int j = 1; j <= i; j++) {
			f[i][j] = f[i - 1][j - 1] + 1LL * f[i - 1][j] * (j - 1) % p;
			if (f[i][j] >= p) {
				f[i][j] -= p;
			}
		}
	}//子问题一预处理

	fact[0] = 1; C[0] = 1;
	for (int i = 1; i < N; i++) {
		fact[i] = 1LL * fact[i - 1] * i % p;
	}//阶乘预处理

	for (int i = 1; i <= m && i < N; i++) {
		C[i] = 1LL * C[i - 1] * (m - i + 1) % p;
	}//组合数预处理
	s[0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= l[i]; j++) {
			gra[i][j] = 1LL * s[i - 1] * f[l[i]][j] % p * C[j] % p;
			if (i > 1 && j <= l[i - 1]) {
				gra[i][j] -= 1LL * fact[j] * gra[i - 1][j] % p * f[l[i]][j] % p;
				if (gra[i][j] < 0) {
					gra[i][j] += p;
				}
			}
			s[i] += gra[i][j];
			if (s[i] >= p) {
				s[i] -= p;
			}
		}
	}
	cout << s[n] << endl;
	return;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	while (cin >> n >> m >> p) {
		solve();
	}
	return 0;
}
/*
	i raised a cute kitty in my code,
	my friend who pass by can touch softly on her head:)

		 /l、
   Meow~(゚、 。7
		 |、 ~ヽ
		 じしf_,)ノ

*/
posted @   TomiokapEace  阅读(134)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示