CF1178F1 Short Colorful Strip

XLV.CF1178F1 Short Colorful Strip

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

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

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

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

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

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

\(f[i,j]=\sum\limits_{k=i}^{p_{mp}}\sum\limits_{l=p_{mp}}^jf[i,k-1]*f[k,p_{mp}-1]*f[p_{mp}+1,l]*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]*f[k,p_{mp}-1])*(\sum\limits_{l=p_{mp}}^jf[p_{mp}+1,l]*f[l+1,j])\)

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

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

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,num[510],f[510][510];
int main(){
	scanf("%d%d",&n,&n);
	for(int i=1;i<=n;i++)scanf("%d",&num[i]);
	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 mp=i;
		for(int k=i;k<=j;k++)if(num[k]<=num[mp])mp=k;
		int A=0,B=0;
		for(int k=mp;k>=i;k--)(A+=(1ll*f[i][k-1]*f[k][mp-1]%mod))%=mod;
		for(int l=mp;l<=j;l++)(B+=(1ll*f[mp+1][l]*f[l+1][j]%mod))%=mod;
		f[i][j]=1ll*A*B%mod;
	}
	printf("%d\n",f[1][n]);
	return 0;
} 

posted @ 2021-03-30 16:12  Troverld  阅读(67)  评论(0编辑  收藏  举报