题解 P2476 【[SCOI2008]着色方案】
Bartholomew · · 题解
~By Bartholomew~
首先我们会发现,最难的莫过于对于 dp[i] (i 表示位置) 的转移,
当然我们会不知道对于某一些非法状态的转移的判断,所以我发现自己 G_G 了!
那么我们如果对于这一题 , 发现 k 和 c[i] 的数值都十分的小! 于是我们来找方案了解决它,因为我们可以暴力开 5 维来记录变化
dp[a][b][c][d][e][last]
表示某颜色只能涂一下的有 a 个,能涂2下的颜色b个,...3个...c个...还有就是上一次的涂的颜色是 last ,如last = 4 表示上一次用的是能涂 4 下的颜色中的某一个!
那么我们怎么转移呢?
发现:
我们用现在能涂 一下的颜色涂色,就是 ans+= a * query(a-1,b,c,d,e,1);
但是如果 我们上一次用的是能涂 2 下的颜色,那么会产生什么问题? 就是在这一次的时候它就变成的只能涂 1 下的颜色,所以现在的 a 种能涂 1 下 的颜色 我们只能选(a-1) 种 可能
以此类推下去...(看代码就明白了!) 别忘了取模 1e9+7!
//代码故意留了一个小错误,希望是阻止大家直接ctrl+a,ctrl+c ! >_<
// luogu-judger-enable-o2
#pragma GCC optimize(3)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define ll long long
const ll MOD = 1000000007;
using namespace std;
int n,x,t[6];
ll dp[16][16][16][16][16][6];
inline ll DFS(int a,int b,int c,int d,int e,int last)
{
if(dp[a][b][c][d][e][last]!=-1) return dp[a][b][c][d][e][last];
if(a+b+c+d+e==0) return 1;
ll res = 0;
if(a) res += (a-(last==2)) * DFS(a-1,b,c,d,e,1);
if(b) res += (b-(last==3)) * DFS(a+1,b-1,c,d,e,2);
if(c) res += (c-(last==4)) * DFS(a,b+1,c-1,d,e,3);
if(d) res += (d-(last==5)) * DFS(a,b,c+1,d-1,e,4);
if(e) res += e * DFS(a,b,c,d+1,e-1,5);
dp[a][b][c][d][e][last] = res%MOD;
return dp[a][b][c][d][e][last];
}
int main(int argc, char const *argv[])
{
scanf("%d",&n);
for(;n;n--) scanf("%d",&x),t[x]++;
memset(dp,-1,sizeof dp);
printf("%lld\n",DFS(t[1],t[2],t[3],t[4],t[5],0));
return main();
}