Codeforces Round #100 E. New Year Garland
好题让我刷新很多对dp状态的观念。
1、先让我们不考虑第二个条件,也就是相邻两层颜色集合不同。
那么显然很容易得到答案为
为什么呢其实显然,一层第一个位置可以填个颜色,后面每个位置不能与前面位置相同,
则填,一层总和就是。
但是先在多了一个条件相邻两层所选集合不能相同。
2、那么怎么办?很容易想到DP,表示前i层满足条件的所有方案数
容易得到一个错误的转移方程
这个方程的意思是g(i)第i层选了所有能选的方案数,然后再减去g(i-1)即 i和i-1层冲突的方案数
有两个错误
(1)和层冲突的方案数并不是,因为层与层除了一一对应相等,调换顺序也可以,因为只要集合一样即可。
(2)假如说的话那么包括一些颜色集合大小可能大于第i层的,那么一定会多减去一部分。
根据上面两个错误,我们能反推出一道新题目。
即l[i]满足单调,且相邻层不相等的方案数,就可以用前面的简单递推了。
3、前面说了那么多,无不指向一点——————我们需要多给加一维,即用了多少颜色,这要我们就能很方便的处理 2、(1)(2)内的两个问题了
(1)既然有了颜色一维,就可以算出这i与i-1层冲突的方案数。
(
(2)以为有了颜色数量这一层,那么我们减去i与i-1层冲突层的数量时候,可以根据i的颜色数量来减去。
这样就很好解决了前两个问题。
4、回到前面的,做这题的时候我才发现一直把这东西搞混了
其实求的是颜色无标号的方案。
(
为什么呢?假设有编号,首先这样推出的选择序列一定时颜色小的出现在颜色大的前面。
这样的序列就对应无标号方案,假设有标号那么
存在12234,13342这样的相同的情况,总会出现第一个小于另一种情况的方案不会算上。
不同无标号的方案也一定算一个答案。
所有以后题目:有5种颜色,染色1000个地盘,相邻的不能同种颜色,问选其中j种颜色染色方案数。
不能求完就完了还得乘上
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+10,M = 5010;
int f[M][M],l[N],g[2][M];
int n,m,MOD,mi[N],jie[N];
void init(){
f[0][0] = 1;
for(int i = 1;i<M;++i){
for(int j = 1;j<=i;++j){
f[i][j] = (f[i-1][j-1]+(LL)f[i-1][j]*(j-1))%MOD;
}
}
mi[0] = 1;
for(int i = 1;i<=m;++i){
mi[i] = (LL)mi[i-1]*(m-i+1)%MOD;
}
jie[0] = 1;
for(int i = 1;i<N;++i)jie[i] = (LL)jie[i-1]*i%MOD;
}
int main(){
// freopen("a.txt","r",stdin);
scanf("%d%d%d",&n,&m,&MOD);
init();
for(int i = 1;i<=n;++i)scanf("%d",&l[i]);
int s = 1;
for(int i = 1;i<=n;++i){
for(int j = 1;i>=2&&j<=l[i-2];++j){
g[i&1][j] = 0;
}
int mn = min(m,l[i]);
for(int j = 1;j<=mn;++j){
g[i&1][j] =
(LL)mi[j]*f[l[i]][j]%MOD*s%MOD
- (LL)g[(i-1)&1][j]*jie[j]%MOD*f[l[i]][j]%MOD;
g[i&1][j]%=MOD;
}
s = 0;
for(int j = 1;j<=mn;++j){
s += g[i&1][j];
s %= MOD;
}
}
s = (s%MOD+MOD)%MOD;
cout<<s<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人