[luogu2476][bzoj1079][SCOI2008]着色方案【动态规划】
题目描述
有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。所有油漆刚好足够涂满所有木块,即c1+c2+…+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。
分析
很多网上的题解都讲的不怎么清楚,我将个人思考到一发WAAC的过程清楚地讲一遍。
首先考虑如何定义状态,一眼就发现了\(c_i<=5\),说明什么,我们可以直接将各个颜色还剩下多少的个数都压到状态中,也就是一个五维的状态。而且题目很明显的发现如果定义各个颜色还有多少个,那么需要用15维,数组直接爆炸。
但是题目要求不能相邻,因为我们已经采取了用个数作为前面的5个状态,那么参考chess的思路,排列组合来排除是否是相邻的,这个待会再说。说的明白一点,就是在定义\(1\)维状态,表示上一个格子我们用的是个数是\(lst\)颜色。
总结一下:\(f[i1][i2][i3][i4][i5][lst]\),\(i_i\)表示的是\(i\)颜色还有\(i_i\)个,前一个涂得颜色是\(lst\)个颜色时方案总数。
我们把这个放棋子的过程,按照从左到右的顺序。
接下来我们思考决策。我们举3个例子,分别是我们放的颜色是\(1\)和\(3\)和\(5\)。
如果我们当前放的颜色是个数为\(1\)的,那么分成两种情况:
- 如果lst=2,那么说明原来是一个是从\(2\)个颜色中取出了一个颜色,变成了个数为\(1\)的颜色,从而得出我们现在放的颜色就是现在有\(1\)个的颜色,那么不能重复,就说明剩下来的\(i1-1\)个一个的颜色都可以放到这个颜色中。
- 如果不是2的话,就和上面的情况刚好相反,也就是之前放的颜色不会和我们现在放的颜色不会冲突,乘法原理可以得到方程。
总结一下转移方程
\[if (lst=2) f[i1][i2][i3][i4][i5][lst] += (i1 - 1) * f[i1-1][i2][i3][i4][i5][1]\]
否则
\[f[i1][i2][i3][i4][i5][lst] += i1*f[i1-1][i2][i3][i4][i5][1]\]
如果我们放的颜色个数为\(3\),这种情况和\(2\)以及\(4\)是相同的,以3为例:
- 如果lst=4,那么参照前面的思路,现在这个颜色就是个数为\(3\)个的颜色,那么如果要将\(3\)放进去,那么会是剩下来个数为\(2\)的颜色个数会\(+1\),让个数为\(3\)的颜色个数\(-1\),
- 反之也就是之前放的颜色不会和我们现在放的颜色不会冲突,乘法原理可以得到方程。
总结一下转移方程
\[if (lst=4) f[i1][i2][i3][i4][i5][lst]+=(i3-1)*f[i1][i2+1][i3-1][i4][i5][3]\]
否则
\[f[i1][i2][i3][i4][i5][lst]+=i3*f[i1][i2+1][i3-1][i4][i5][3]\]
如果我们放的个数是\(5\):
因为不可能有颜色可以放了之后还有\(5\)个,那么就直接乘法原理就可以的到房成了。
总结一下转移方程
\[f[i1][i2][i3][i4][i5][lst] += i5*f[i1-1][i2][i3][i4][i5][5]\]
状态转移方程完成了,那么接下来就是状态的边界条件。很清楚的是,一开始的时候无论取哪一个颜色方案数都只有\(1\),那么也就是\(f[0][0][0][0][0][i]=1\),其他都赋值为0。
因为考虑到这道题目线性推常数较大,就采用了记忆化搜索来实现DP。
ac代码
#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') fl = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= fl;
}
ll f[16][16][16][16][16][6];
int d[6];
int n;
ll dfs(int i1, int i2, int i3, int i4, int i5, int lst) {
if (f[i1][i2][i3][i4][i5][lst]) return f[i1][i2][i3][i4][i5][lst];
ll res = 0;
if (i1 > 0) {
if (lst == 2) res = (res + (i1 - 1) * dfs(i1 - 1, i2, i3, i4, i5, 1)) % mod;
else res = (res + i1 * dfs(i1 - 1, i2, i3, i4, i5, 1)) % mod;
}
if (i2 > 0) {
if (lst == 3) res = (res + (i2 - 1) * dfs(i1 + 1, i2 - 1, i3, i4, i5, 2)) % mod;
else res = (res + i2 * dfs(i1 + 1, i2 - 1, i3, i4, i5, 2)) % mod;
}
if (i3 > 0) {
if (lst == 4) res = (res + (i3 - 1) * dfs(i1, i2 + 1, i3 - 1, i4, i5, 3)) % mod;
else res = (res + i3 * dfs(i1, i2 + 1, i3 - 1, i4, i5, 3)) % mod;
}
if (i4 > 0) {
if (lst == 5) res = (res + (i4 - 1) * dfs(i1, i2, i3 + 1, i4 - 1, i5, 4)) % mod;
else res = (res + i4 * dfs(i1, i2, i3 + 1, i4 - 1, i5, 4)) % mod;
}
if (i5 > 0) {
res = (res + i5 * dfs(i1, i2, i3, i4 + 1, i5 - 1, 5)) % mod;
}
return f[i1][i2][i3][i4][i5][lst] = res % mod;
}
int main() {
int k;
read(k);
for (int i = 1; i <= k; i ++) {
int x;
read(x);
d[x] ++;
}
for (int i = 1; i <= 5; i ++) f[0][0][0][0][0][i] = 1;
printf("%lld\n", dfs(d[1], d[2], d[3], d[4], d[5], 0) % mod);
return 0;
}
[luogu2476][bzoj1079][SCOI2008]着色方案【动态规划】的更多相关文章
- BZOJ1079 [SCOI2008]着色方案 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1079 题目概括 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的 ...
- BZOJ1079:[SCOI2008]着色方案(DP)
Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个 ...
- BZOJ1079 [SCOI2008]着色方案 【dp记忆化搜索】
题目 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+-+ck=n.相邻两个木块涂相同色显得很难看 ...
- BZOJ1079: [SCOI2008]着色方案 (记忆化搜索)
题意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很 ...
- 2018.10.20 bzoj1079: [SCOI2008]着色方案(多维dp)
传送门 dp妙题. f[a][b][c][d][e][last]f[a][b][c][d][e][last]f[a][b][c][d][e][last]表示还剩下aaa个可以用一次的,还剩下bbb个可 ...
- BZOJ1079 [SCOI2008]着色方案[组合计数DP]
$有a_{1}个1,a_{2}个2,...,a_{n}个n(n<=15,a_{n}<=5),求排成一列相邻位不相同的方案数.$ 关于这题的教训记录: 学会对于复杂的影响分开计,善于发现整体 ...
- bzoj1079: [SCOI2008]着色方案
dp.以上次染色时用的颜色的数量和每种数量所含有的颜色作状态. #include<cstdio> #include<algorithm> #include<cstring ...
- 【记忆化搜索】bzoj1079 [SCOI2008]着色方案
#include<cstring> #include<cstdio> using namespace std; #define MOD 1000000007 typedef l ...
- bzoj1079: [SCOI2008]着色方案
ci<=5直接想到的就是5维dp了...dp方程YY起来很好玩...写成记忆化搜索比较容易 #include<cstdio> #include<cstring> #inc ...
随机推荐
- windows中在vs code终端使用bash
vs code Visual Studio Code的缩写,很好用的一个编辑器. 终端 vs code的终端(命令行)在windows中,默认使用的是powershell,如下图所示: powersh ...
- CodeIgniter框架对数据库查询结果进行统计
假设有一个user表,如果要查询符合条件sex=male的记录数量,有下面几种方法: 方法一:先取回所有符合条件的记录,再count $res = $this->db->query(&qu ...
- MapReduce过程<原创>
一.预处理阶段 二.Map阶段 一个Map任务被JobTracker(管家)分配到多个TaskTracker(弟弟)执行,如下图所示,弟弟的map()只负责拆分,虽然map()输出两个相同的键值对,但 ...
- TortoiseGit push免输密码
(ฅ>ω<*ฅ) 噫又好了~ TortoiseGit push免输密码的方法 – 晨旭的博客~https://www.chenxublog.com/2016/03/04/tortoiseg ...
- 墨者学院——密码学加解密实训(Base64转义)
地址:https://www.mozhe.cn/bug/detail/SW5ObnVFa05vSHlmTi9pcWhRSjRqZz09bW96aGUmozhe 在靶场中找到内容 解密 访问直接得key
- java 从键盘录入的三种方法
详细内容连接 https://blog.csdn.net/StriverLi/article/details/52984066
- Python对elasticsearch的CRUD
一.官网提供的Elasticsearch的Python接口包 1.github地址:https://github.com/elastic/elasticsearch-dsl-py 2.安装:pip i ...
- linux audit审计(4)--audit的日志切分,以及与rsyslog的切分协同使用
audit的规则配置稍微不当,就会短时间内产生大量日志,所以这个规则配置一定要当心.当audit日志写满后,可以看到如下场景: -r-------- 1 root root 8388609 Mar 3 ...
- IntelliJ IDEA详情
详情请参考http://www.phperz.com/article/15/0923/159043.html
- 【理论】X理论、Y理论及Z理论
道格拉斯·麦格雷戈(Douglas Mcgregor)把对人的基本假设作了区分,即X理论和Y理论.X理论认为:人们总是尽可能地逃避工作,不愿意承担责任,因此要想有效地进行管理,实现组织的目标,就必 ...