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