1. 程式人生 > >BZOJ 1079: [SCOI2008]著色方案(巧妙的dp)

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

result ret stdout 方案 code get 有一種 using spa

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\)時間復雜度做法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)