CF1178F1 Short Colorful Strip 题解

发布时间 2023-10-10 16:26:39作者: xuantianhao

Short Colorful Strip

考虑设 \(f[i,j]\) 表示:假设区间 \([i,j]\) 里面一开始所有格子的颜色都是相同的,那么,染成目标状态共有多少种染法。

我们找到 \([i,j]\) 中最小的那个颜色,设为 \(mp\)。则显然,我们下一步要染上 \(mp\) 这种颜色。

设最终在位置 \(p_{mp}\) 上染上了颜色\(mp\)。则我们可以在所有这样的区间 \([k,l]\) 上染上 \(mp(i \le k \le p_{mp} \le l \le j)\)

或许你会以为这意味着 \(f[i,j]=\sum\limits_{k=i}^{p_{mp}}\sum\limits_{l=p_{mp}}^jf[i,k-1] \times f[k,l] \times f[l+1,j]\)

但是,这样是错误的,因为当 \([k,l]=[i,j]\) 时,\(f[i,j]\) 便无法从子状态转移过来!

我们考虑拆开 \(f[k,l]\)。因为再往后的染色中,位置 \(p_{mp}\) 一定没有再被染色过,因此有 \(f[k,l]=f[k,p_{mp}-1] \times f[p_{mp}+1,l]\)

\[f[i,j]=\sum\limits_{k=i}^{p_{mp}} \sum\limits_{l=p_{mp}}^{j} f[i,k-1] \times f[k,p_{mp}-1] \times f[p_{mp}+1,l] \times f[l+1,j] \]

特殊定义一下,对于 \(f[i,j]\),如果 \(i>j\),则 \(f[i,j]=1\)。这也是为了转移的正确(在应用上述式子时可能会调用到这样的 \(f[i,j]\)

上面的转移是 \(O(n^4)\) 的;但当我们拆开两个 \(\sum\),就可以把它化成 \(O(n^3)\) 的。

\[f[i,j]=(\sum\limits_{k=i}^{p_{mp}}f[i,k-1] \times f[k,p_{mp}-1]) \times (\sum\limits_{l=p_{mp}}^jf[p_{mp}+1,l] \times f[l+1,j]) \]

前后两个括号内的内容互不干涉,故可以分开计算。

复杂度 \(O(n^3)\)

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int N=510;
int n,m;
int num[N],f[N][N];
inline int read(){
    char c=getchar();int f=1,x=0;
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) num[i]=read();
    for(int i=1;i<=n+1;i++)for(int j=0;j<i;j++) f[i][j]=1;
    for(int i=1;i<=n;i++) f[i][i]=1;
    for(int l=2;l<=n;l++){
		for(int i=1,j=i+l-1;j<=n;i++,j++){
		    int x=i,A=0,B=0;
		    for(int k=i;k<=j;k++) if(num[k]<=num[x]) x=k;
		    for(int k=x;k>=i;k--) (A+=(1LL*f[i][k-1]*f[k][x-1]%mod))%=mod;
		    for(int k=x;k<=j;k++) (B+=(1LL*f[x+1][k]*f[k+1][j]%mod))%=mod;
		    f[i][j]=1LL*A*B%mod;
		}
	}
    printf("%d\n",f[1][n]);
    return 0;
}