习题:Short Colorful Strip(DP)

题目

传送门

思路

如果一个区间没有被染色,或者被全部染色

那么这个区间是很容易被计算的,也就是指我们可以考虑设计这种状态来计算答案

设$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;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/13395538.html