有n個木塊排成一行,從左到右依次編號為1~n。你有k種顏色的油漆,其中第i種顏色的油漆足夠塗ci個木塊。真是一道大神題啊。一開始看到時亂想一大推,但其實原來這題如此巧妙。所有油漆剛好足夠塗滿所有木塊,即c1+c2+…+ck=n。相鄰兩個木塊塗相同色顯得很難看,所以你希望統計任意兩個相鄰木塊顏色不同的著色方案。
其實像這樣統計方案的問題,一般就是用dp來做的,只不過這題dp用記憶化搜尋罷了。
先定義乙個f陣列,f[a1][a2][a3][a4][a5][x]中ai表示還剩下i次機會塗色的顏色種類數,x表示上一次塗色用的是a幾。為什麼這樣呢,因為決定現在這個顏色是否能塗只跟上一次塗色有關。
那麼問題來了,如何快速繼承狀態呢?
首先得弄明白一點,當前選什麼樣的顏色不重要,只需滿足相鄰條件就行,還剩下多少次能塗才是重要的。舉個例子,假設你要選還剩下3次機會塗色的顏色,只需讓a3(或a3-1,為什麼等一下講)乘上f[a1][a2+1][a3-1][a4][a5][x](為什麼等一下講)就行。
明白後就方便繼承了。但還有幾點需要注意,假設你選了還剩下3次機會塗色的顏色,那你a2就要+1,a3要-1,因為你選了以後它就變成了還剩下2次機會塗色的顏色。相鄰條件似乎是最大的難點,但我們知道了你上次選了還剩下i次機會塗色的顏色,如果你這次要選還剩下i-1次機會塗色的顏色,那你就不能再選上次選過的顏色,不然會相鄰,這就是a(i-1)-1乘而不是a(i-1)乘的原因。
那麼這題便迎刃而解了。
#include
#include
#include
#include
#include
#define mod 1000000007
using
namespace
std;
int s[6];
long
long f[17][17][17][17][17][7];
long
long dfs(int a1,int a2,int a3,int a4,int a5,int x)
if(a2!=0)
if(a3!=0)
if(a4!=0)
if(a5!=0)
f[a1][a2][a3][a4][a5][x]=ans;
return ans;
}int main()
printf("%lld\n",dfs(s[1],s[2],s[3],s[4],s[5],0));
return
0;}
BZOJ 1079 SCOI2008 著色方案
題目 分析 一看就覺得是dp或者直接排列組合公式或者容斥?我就只想到dp的,我們用dp i j 表示前i種顏色,排列出有j對相鄰一樣顏色的方案數。當出現乙個新的顏色時,我們把這個顏色插板法插進去,我們要列舉插入的方式,可能插到相鄰顏色一樣的中間,或者不是,然後進行狀態轉移.具體看 include i...
BZOJ1079 SCOI2008著色方案 DP
只能想到 5 15 的方法。我們要利用起 ci比較小這個性質,f a b c d e last 表示有a 種顏色用了1個,b種顏色用了2個 上一次染色用的是剩餘 last 個的顏色,轉移就是f a,b,c,d,e,last a last 2 f a 1,b,c,d,e b last 3 f a 1,...
bzoj1079 SCOI2008 著色方案
有n個木塊排成一行,從左到右依次編號為1 n。你有k種顏色的油漆,其中第i種顏色的油漆足夠塗ci個木塊。所有油漆剛好足夠塗滿所有木塊,即c1 c2 ck n。相鄰兩個木塊塗相同色顯得很難看,所以你希望統計任意兩個相鄰木塊顏色不同的著色方案。第一行為乙個正整數k,第二行包含k個整數c1,c2,ck。輸...