洛谷P2476 [SCOI2008]着色方案

题目:https://daniu.luogu.org/problemnew/show/P2476

题目背景

四川NOI省选第二试

题目描述

有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i 种颜色的油漆足够涂ci 个木块。所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。

输入输出格式

输入格式:

第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。

输出格式:

输出一个整数,即方案总数模1,000,000,007的结果。

输入输出样例

输入样例#1:

3
1 2 3

输出样例#1:

10

输入样例#2:

5
2 2 2 2 2

输出样例#2:

39480

输入样例#3:

10
1 1 2 2 3 3 4 4 5 5

输出样例#3:

85937576

说明

50%的数据满足:1 <= k <= 5, 1 <= ci <= 3

100%的数据满足:1 <= k <= 15, 1 <= ci <= 5

解析

这属于比较简单的省选dp吧。

一开始看感觉下不去手,隐隐约约觉得是dp。

当看到ci<=5时眼前一亮。

这么小的范围,也许要有这么多维吧。

然后就想到了中国象棋这道题https://www.luogu.org/problemnew/show/2051

好了思路确立。

先想一想dfs的打法。

设a,b,c,d,e分别代表ci=1,ci=2,...,ci=5的颜色。

那么ans=dfs(a,b,c,d,e,last(回头说用处))。

我们考虑转移,

a,b,c,d,e的状态可以从

a-1,b,c,d,e

a+1,b-1,c,d,e(假设用了ci=2的其中一个,那么这个ci=2就会变成ci=1,所以a要+1,后面同理)

a,b+1,c-1,d,e

a,b,c+1,d-1,e

a,b,c,d+1,e-1

的状态转移过来。

我们先单独考虑一下a,b,c,d,e转化到a+1,b-1,c,d,e的情况吧。

这相当于用了ci=2的颜色一个。

那么一共有几种可以用呢?

题目要求颜色相同的不能靠在一块。

我们设上次用的是last。

此处要用ci=2的,

如果上次用的是ci=3的,则所有ci=2中有一个颜色便是上次ci=3转移过来的。

如果这次再用这个,则相同颜色在一块了,可选数-1。

所以,dfs(a,b,c,d,e,last)转化成dfs(a+1,b-1,c,d,e,2)的贡献是:(b-(last==3))*dfs(a+1,b-1,c,d,e,2);

其余同理,dfs思路确立。

然后这个过程转化成记忆化即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll long long
 8 #define mod 1000000007
 9 ll k,re;
10 ll c[6];
11 ll f[16][16][16][16][16][6];
12 ll dfs(ll a,ll b,ll c,ll d,ll e,ll last){
13     if (f[a][b][c][d][e][last]) return f[a][b][c][d][e][last];
14     ll tot=0;
15     if (!a&&!b&&!c&&!d&&!e){
16         f[0][0][0][0][0][last]=1;
17         return 1;
18     }
19     if (a) tot=(tot+((a-(last==2))*dfs(a-1,b,c,d,e,1))%mod)%mod;
20     if (b) tot=(tot+((b-(last==3))*dfs(a+1,b-1,c,d,e,2))%mod)%mod;
21     if (c) tot=(tot+((c-(last==4))*dfs(a,b+1,c-1,d,e,3))%mod)%mod;
22     if (d) tot=(tot+((d-(last==5))*dfs(a,b,c+1,d-1,e,4))%mod)%mod;
23     if (e) tot=(tot+(e*dfs(a,b,c,d+1,e-1,5))%mod)%mod;
24     return f[a][b][c][d][e][last]=tot;
25 }
26 int main(){
27     scanf("%lld",&k);
28     for (int i=1;i<=k;++i){
29         scanf("%lld",&re);
30         c[re]++;
31     }
32     printf("%lld",dfs(c[1],c[2],c[3],c[4],c[5],233666));
33     return 0;
34 }
35                     

时间: 2024-08-28 21:23:48

洛谷P2476 [SCOI2008]着色方案的相关文章

洛谷 2476 [SCOI2008]着色方案

50%的数据满足:1 <= k <= 5, 1 <= ci <= 3 100%的数据满足:1 <= k <= 15, 1 <= ci <= 5 [题解] 本题中ci很小,因此可以直接5维保存可以涂i块的油漆有多少种颜色.然后利用乘法原理进行DP 1 #include<cstdio> 2 #include<algorithm> 3 #define LL long long 4 #define rg register 5 #define

LUOGU P2476 [SCOI2008]着色方案

传送门 解题思路 毒瘤题,,刚开始写了个奇奇怪怪的哈希,结果T了5个点..后来深(kan)入(le)思(ti)考(jie),发现c的范围很小,设$f[a][b][c][d][e][pre]?$表示还能涂一个格子的有a个,两个格子的有b个...pre表示上一个涂的颜色,转移看代码,比较好想. #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN =

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

1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1079 Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的

[SCOI2008] 着色方案[高维dp]

321. [SCOI2008] 着色方案 ★★★   输入文件:color.in   输出文件:color.out   简单对比时间限制:1 s   内存限制:64 MB 题目背景: 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i 种颜色的油漆足够涂ci 个木块.所有油漆刚好足够涂满所有木块,即 c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案.[输入]第一行为一个正整数k,第二行包含k个整数c1, c2,

bzoj1079: [SCOI2008]着色方案

ci<=5直接想到的就是5维dp了...dp方程YY起来很好玩...写成记忆化搜索比较容易 #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #

BZOJ 1079: [SCOI2008]着色方案 DP

1079: [SCOI2008]着色方案 Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案. Input 第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck. Output 输出一个整数,即方案总数模1,000,000,007的结果. Sample Inp

bzoj1079: [SCOI2008]着色方案(dp)

1079: [SCOI2008]着色方案 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2133  Solved: 1287[Submit][Status][Discuss] Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案.

BZOJ 1079: [SCOI2008]着色方案(巧妙的dp)

BZOJ 1079: [SCOI2008]着色方案(巧妙的dp) 题意:有\(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

bzoj1079 [SCOI2008]着色方案

Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案. Input 第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck. Output 输出一个整数,即方案总数模1,000,000,007的结果. Sample Input 3 1 2 3 Sample Out