習題:Short Colorful Strip(DP)
阿新 • • 發佈:2020-07-29
題目
思路
如果一個區間沒有被染色,或者被全部染色
那麼這個區間是很容易被計算的,也就是指我們可以考慮設計這種狀態來計算答案
設\(dp[i][j]\)為\(i\)到\(j\)這個區間沒有被染色或者全部被染色的染成正確方案的方案數
如果當前是第\(i\)種顏色,設其的位置為\(p_i\),那麼\(l\)~\(p_i-1\)和\(p_i+1\)到\(r\)的位置是可以任意染的
即我們將一個區間分成了4段
\(dp[l][r]=\sum_{k_1=l}^{p_i-1}\sum_{k_2=p_2+1}^{r}dp[l][k_1]*dp[k_1+1][p_i-1]*dp[p_i+1][k_2]*dp[k_2+1][r]\)
很明顯,這個轉移是\(O(n^2)\)的
但是我們觀察這個式子,很明顯可以化簡成為
\(dp[l][r]=\sum_{k_1=l}^{p_i-1}dp[l][k_1]dp[k_1+1][p_i-1]*\sum_{k_2=p_i+1}^{r}dp[p_i+1][k_2]dp[k_2+1][r]\)
即轉移就可以變成\(O(n)\)的
總共的時間複雜度為$O(n^3) $
程式碼
#include<iostream> #include<cstring> using namespace std; const int mod=998244353; long long dp[505][505]; //l~r未被染色或者染成同一種顏色之後染成正確顏色的種類數 int n,m; int a[505]; long long dfs(int l,int r) { if(l>r) return 1; if(l==r) return dp[l][r]=1; if(dp[l][r]!=-1) return dp[l][r]; int _ind=-1; int minn=(1<<30); for(int i=l;i<=r;i++) { if(a[i]<minn) { minn=a[i]; _ind=i; } } long long s1=0,s2=0; for(int len=0;_ind+len<=r;len++) s1=(s1+dfs(_ind+1,_ind+len)*dfs(_ind+len+1,r))%mod; for(int len=0;_ind-len>=l;len++) s2=(s2+dfs(_ind-len,_ind-1)*dfs(l,_ind-len-1))%mod; dp[l][r]=(max(s1,1ll)*max(s2,1ll))%mod; return dp[l][r]; } int main() { memset(dp,-1,sizeof(dp)); cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; cout<<dfs(1,n); return 0; }