题意

有\(n\)个木块排成一行,从左到右依次编号为\(1\)~\(n\)。你有\(k\)种颜色的油漆,其中第\(i\)种颜色的油漆足够涂\(c_i\)个木块。所有油漆刚好足够涂满所有木块,即\(\sum\limits _{i=1}^{k}c_i=n\)。统计任意两个相邻木块颜色不同的着色方案。(\(1 \le k \le 15\) ,\(1\le c_i \le 5\))

题解

特别巧妙的dp!一开始容易想到用\({c_i}^k\)时间复杂度做法QAQ,并没有什么用。

但是可以启发我们也许可以用\(k^{c_i}\)算法去解决问题。然而我还是不会。。

我就看了一下别人的博客2333 发现dp很巧妙

我们可以存储剩余能涂\(q\)个木块的油漆还剩多少种。这样时空复杂度就都降到\(k^{c_i}\)了。

所以就有dp[a][b][c][d][e]来记录答案(a,b,c,d,e分别表示1,2,3,4,5的种数),所以就有

dp[a][b][c][d][e] = dp[a - 1][b][c][d][e] * a + dp[a + 1][b - 1][c][d][e] * b + dp[a][b + 1][c - 1][d][e] * c + dp[a][b][c + 1][d - 1][e] * d + dp[a][b][c][d + 1][e - 1] * e; (之间的+1,-1就是前面一种颜料从能涂q块,变成q-1了)

但这并不符合题目要求(不然一个组合数就结束了),所以我们多记一个状态last表示上一次是用能涂last次的油漆涂的,如果这次我们用last - 1的话,就有一种颜料重复了,所以就要减去一种的贡献。

这样就基本做完了,但dp顺序有点麻烦,所以就上记忆化吧,十分简短易写,强力安利!

具体dp方程见程序吧。。不想写了QAQ

代码

/**************************************************************
Problem: 1079
User: zjp_shadow
Language: C++
Result: Accepted
Time:752 ms
Memory:67848 kb
****************************************************************/ #include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std; bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
return x * fh;
} void File () {
#ifdef zjp_shadow
freopen ("P1079.in", "r", stdin);
freopen ("P1079.out", "w", stdout);
#endif
} const int N = 17, Mod = 1e9 + 7;
typedef long long ll; ll dp[N][N][N][N][N][6]; ll Dp(int a, int b, int c, int d, int e, int last) {
if ((a | b | c | d | e) == 0) return 1;
ll &res = dp[a][b][c][d][e][last];
if (~res) return res; res = 0;
if (a) res += Dp(a - 1, b, c, d, e, 1) * (a - (last == 2) );
if (b) res += Dp(a + 1, b - 1, c, d, e, 2) * (b - (last == 3) );
if (c) res += Dp(a, b + 1, c - 1, d, e, 3) * (c - (last == 4) );
if (d) res += Dp(a, b, c + 1, d - 1, e, 4) * (d - (last == 5) );
if (e) res += Dp(a, b, c, d + 1, e - 1, 5) * e;
res %= Mod;
return res;
} int main () {
File();
int n = read(), a[6] = {0};
For (i, 1, n) ++ a[read()];
Set(dp, -1);
printf ("%lld\n", Dp(a[1], a[2], a[3], a[4], a[5], 0) );
return 0;
}

BZOJ 1079: [SCOI2008]着色方案(巧妙的dp)的更多相关文章

  1. bzoj 1079: [SCOI2008]着色方案 DP

    1079: [SCOI2008]着色方案 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 803  Solved: 512[Submit][Status ...

  2. BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

    1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

  3. BZOJ 1079 [SCOI2008]着色方案

    http://www.lydsy.com/JudgeOnline/problem.php?id=1079 思路:如果把每种油漆看成一种状态,O(5^15)不行 DP[a][b][c][d][e][f] ...

  4. bzoj 1079: [SCOI2008]着色方案【记忆化搜索】

    本来打算把每个颜色剩下的压起来存map来记忆化,写一半发现自己zz了 考虑当前都能涂x次的油漆本质是一样的. 直接存五个变量分别是剩下12345个格子的油漆数,然后直接开数组把这个和步数存起来,记忆化 ...

  5. 【BZOJ】1079: [SCOI2008]着色方案(dp+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1079 只能想到5^15的做法...........................果然我太弱. 其实 ...

  6. BZOJ1079 [SCOI2008]着色方案[组合计数DP]

    $有a_{1}个1,a_{2}个2,...,a_{n}个n(n<=15,a_{n}<=5),求排成一列相邻位不相同的方案数.$ 关于这题的教训记录: 学会对于复杂的影响分开计,善于发现整体 ...

  7. 1079: [SCOI2008]着色方案

    链接 思路 首先是dp,如果直接用每个种颜色的剩余个数做状态的话,复杂度为5^15. 由于c<=5,所以用剩余数量的颜色的种类数做状态:f[a][b][c][d][e][last]表示剩余数量为 ...

  8. bzoj1079: [SCOI2008]着色方案

    ci<=5直接想到的就是5维dp了...dp方程YY起来很好玩...写成记忆化搜索比较容易 #include<cstdio> #include<cstring> #inc ...

  9. [SCOI2008]着色方案

    1079: [SCOI2008]着色方案 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2228  Solved: 1353[Submit][Stat ...

随机推荐

  1. Hive metastore表结构设计分析

    今天总结下,Hive metastore的结构设计.什么是metadata呢,对于它的描述,可以理解为数据的数据,主要是描述数据的属性的信息.它是用来支持如存储位置.历史数据.资源查找.文件记录等功能 ...

  2. centos7安装部署gitlab服务器

    [gitlab需要内存至少4GB]   我这里使用的是centos 7 64bit,我试过centos 6也是可以的! 1. 安装依赖软件 yum -y install policycoreutils ...

  3. PHP执行Session与前端JS之间的关系

    <?php error_reporting(0); $path = './tmp/'; $sess_name = session_name(); echo $sess_name; $sess_i ...

  4. angular2^ typescript 将 文件和Json数据 合并发送到服务器(1.客户端处理)

    首先介绍下框架基本流程   (web > webservice  [前端架构] ) > (nodejs [ 数据中转站 ]) >(api [后台接口]) --web (html  a ...

  5. 速卖通AE平台+聚石塔+奇门 完整教程V2

    公司是跨境电商,在阿里马马的速卖通平台上开有店铺,并且基于速卖通开放平台,自主研发了ERP系统,居今已有3年多的时间了,一直很稳定. 今年初,速卖通AE开放平台改版,并入淘宝开放平台中,我们的麻烦就开 ...

  6. MysqL读写分离的实现-Mysql proxy中间件的使用

    为什么要架设读写分离,这里不做多余的说明,想了解具体原理,请百度或者参考其他帖子.在这里只做大概的配置说明,测试中使用三台服务器 192.168.136.142   主服务器 192.168.136. ...

  7. 初学node.js有感一

    Node.js感悟 一.前言 很久以前就对node.js十分的好奇和感兴趣,因为种种原因没能去深入的认识了解和学习掌握这门技术,最近正好要做一些项目,其中就用到了node.js中的一些东西,所以借着使 ...

  8. Spring data mongodb 聚合,投射,内嵌数组文档分页.

    尽量别直接用 DBObject  ,Spring data mongodb 的api 本来就没什么多大用处,如果还直接用 DBObject 那么还需要自己去解析结果,说动做个对象映射,累不累 Spri ...

  9. scrapy学习总结

    1.为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦 Selector有四个基本的方法(点击相应的方法 ...

  10. Storm+HBase实时实践

    1.HBase Increment计数器 hbase counter的原理: read+count+write,正好完成,就是讲key的value读出,若存在,则完成累加,再写入,若不存在,则按&qu ...