题解 P2476 【[SCOI2008]着色方案】 记忆化DP

~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(a1,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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章