[CF1178 F2] Long Colorful Strip

F2 - Long Colorful Strip

很牛的题!

首先,我们可以将颜色相同的一段区间缩成一个点,那么每次加入一个新的颜色时,最多只能将其所覆盖的那个颜色所属的区间分成三部分(原本:00000000,加入10001111000),也就是增加了两个点,那么也就意味着最终所成的点的个数最多只有2n1个,这样的话,m看着很大,其实也就是O(N)级别的

对于这种区间覆盖的题,优先考虑区间dp

dp[l][r]表示让区间[l,r]合法的方案数,且满足[l,r]中的颜色不会在[l,r]外出现

p为区间[l,r]中最小的颜色,其出现的最早的位置为mnp,最晚的位置为mxp,那么显然有我们可以一开始就让p覆盖区间[a,b][mnp,mxp][a,b]),那么就有转移式

dp[l][r]=a[l,mnp]b[mxp,r]dp[l][a1]×dp[a][b]×dp[b+1][r]

其中,对于dp[a][b],其实就是相当于对于[a,b]的所有方案,直接在每种方案的第一个操作之前给[a,b]覆盖上颜色p即可(总之就是让第一步变成用p覆盖[a,b],具体的,若原本的方案没有这一步,加上即可;否则,若其原本只用p覆盖[s,t][s,t][a,b],因为p也是[a,b]中最小的值,所以原本的用p覆盖[s,t]的这一步也一定是该方案中的第一步)将其补全成覆盖[a,b]即可

但是可以发现,当a=l,b=r时,就转不了了,所以考虑将dp[a][b]拆开

因为p的最早出现位置为mnp,最晚出现位置为mxp,所以显然有所有处于[mnp,mxp]中的颜色的出现区间范围也不会超过[mnp,mxp],这也意味这[mnp,mxp][a,b]分隔成了三个区间[a,mnp1],[mnp,mxp],[mxp+1,b],这三个区间是“独立的”,即它们的颜色集合没有交集

证明的话可以从mnpmxp这两个点下手,因为它们的颜色p是区间[a,b]中最小的颜色,这就意味着区间[a,b]中剩下的所有颜色都不会跨越它们,也就是没有颜色会覆盖上述三个区间中的任意两个,所以所有颜色只会待在对应的一个区间内

dp[a][b]=dp[a][mnp1]×dp[mxp+1][b]×[i,j]dp[i][j]

其中[i,j]表示所有不包含颜色p的、属于区间[mnp,mxp]的极长区间,它实际上如何转移的和上文中dp[a][b]的解释一致

所以我们就得到了最终的式子

dp[l][r]=a[l,mnp]b[mxp,r]dp[l][a1]×dp[a][mnp1]×([i,j]dp[i][j])×dp[mxp+1][b]×dp[b+1][r]

复杂度O(N3)

代码中,只要保证了当前区间[l,r]的最小颜色p的范围属于当前区间,在转移时因为其他转移给dp[l][r]dp[x][y]会保证属于[x,y]的所有颜色只属于[x,y]中,所以最终就一定能保证[l,r]中的所有颜色只属于[l,r]

也就是归纳证明即可

#include<bits/stdc++.h>
using namespace std;
const int N=505,M=1e6+5,MOD=998244353;
int n,m,col[M],dp[N<<1][N<<1],mn[N],mx[N];
void add(int &x,int y){ x+=y; if(x>=MOD) x-=MOD; }
int ad(int x,int y){ x+=y; if(x>=MOD) x-=MOD; return x; }
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d",&col[i]);
		if(col[i]==col[i-1]) --i,--m;
		else (!mn[col[i]])&&(mn[col[i]]=i),mx[col[i]]=i;
	}
	if(m>=(n<<1)) return puts("0"),0;
	for(int i=1;i<=m+1;++i) for(int j=0;j<i;++j) dp[i][j]=1;
	for(int len=1;len<=m;++len)
		for(int l=1,r,p,a,b;l+len-1<=m;++l){
			r=l+len-1,p=N,a=0,b=0;
			for(int k=l;k<=r;++k) p=min(p,col[k]);
			if(mn[p]<l||mx[p]>r) continue;
			for(int k=l-1;k<=mn[p]-1;++k) add(a,1ll*dp[l][k]*dp[k+1][mn[p]-1]%MOD);
			for(int k=mx[p];k<=r;++k) add(b,1ll*dp[mx[p]+1][k]*dp[k+1][r]%MOD);
			dp[l][r]=1ll*a*b%MOD;
			for(int i=mn[p]+1,j=mn[p];i<mx[p];i=(j+=2)){
				for(;col[j+1]!=p;++j) ;
				dp[l][r]=1ll*dp[l][r]*dp[i][j]%MOD;
			}
		}
	printf("%d",dp[1][m]);
	
	return 0;
}

posted @   LuoyuSitfitw  阅读(28)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示