zoukankan      html  css  js  c++  java
  • CF1178F Short/Long Colorful Strip(DP)

    说起来,这题好像也不难……

    先考虑 F1 怎么做。

    既然别的方法都不行不如试试(f_{i,j}) 表示在刚刚准备开始涂 ([i,j]) 中最小编号的颜色之前,整个区间是同色的,且最后能做到 ([i,j]) 变成要求的颜色,且所有连续颜色段要么完全在 ([i,j]) 内,要么完全在 ([i,j]) 外的方案数。(有点绕,好好理解一下)

    那么先找到区间 ([i,j]) 中的最小值 (c),下一步染色的区间 ([l,r]) 一定要满足 (ile lle rle j) 且包括 (p_c),其中 (p_c)(c) 出现的位置。

    由于染色后,([l,r]) 内同色且与不在 ([l,r]) 内的异色,那么整个带子变成了四块。(图片来源:官方题解)

    这是因为,(p_c) 永远不能被重新染色,就把两边分开了;([l,r]) 内和 ([l,r]) 外的已经不同色,后面也不可能变得同色。

    那么这四部分可以单独处理。

    就有转移方程:(f_{i,j}=sumlimits_{l=i}^{p_c}sumlimits_{r=p_c}^jf_{i,l-1}f_{l,p_c-1}f_{p_c+1,r}f_{r+1,j})。这里由于一些边界原因,不妨设 (f_{i+1,i}=1)

    这是一个 (O(n^4)) 做法(在 F1 中 (n=m))。优化的话,发现 (l)(r) 在转移中独立。可以重写:(f_{i,j}=(sumlimits_{l=i}^{p_c}f_{i,l-1}f_{l,p_c-1})(sumlimits_{r=p_c}^jf_{p_c+1,r}f_{r+1,j}))

    时间复杂度 (O(n^3))。还有个大概 (frac{1}{6}) 的常数。

    接下来看看 F2。

    首先这个 (m) 太大了,无论如何都不能直接区间 DP。

    找找性质:

    性质 1:如果两个方格某个时刻开始不同色,那么它们会一直不同色。反过来,如果两个方格最后同色,那么它们始终同色。

    所以,不妨把连续一段相等的压成一个,不影响答案。

    性质 2:(c_i e c_{i+1})(i) 叫做转折点。那么一次染色最多增加两个转折点。

    所以,压缩后如果 (m>2n),这一定是不可能做到的,直接输出 (0)

    那么接下来 (mle 2n),基本上可以按上面的方法来做。不过要稍微修改一下。

    比如考虑序列 2,1,2,答案明显是 (0)。但是我们上面的做法会用 1 把两边分开单独考虑。

    为什么会错呢?因为此时两边不独立。

    其实解决方法也很简单,每次判一下是不是序列中所有 (c) 都在这个区间中。如果不是的话,给这个区间染色后不可能做到里面是 (c),外面也是 (c)

    同时,此时这个区间也分成了不止四段。不过问题不大,前后四段还是通过上面的方法转移,中间几段是一定取满的,直接乘上去就好了。

    时间复杂度 (O(n^3+m)),有个大概 (frac{4}{3}) 的常数。在 CF 神机+ 6s 时限下完全不用怕。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=1111,mod=998244353;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,m,m_,a[1111111],lft[maxn],rig[maxn],f[maxn][maxn];
    int main(){
    	n=read();m_=read();
    	while(m_--){
    		int x=read();
    		if(x!=a[m]) a[++m]=x;
    	}
    	if(m>2*n) return puts("0"),0;
    	MEM(lft,0x3f);
    	FOR(i,1,m) lft[a[i]]=min(lft[a[i]],i),rig[a[i]]=max(rig[a[i]],i);
    	FOR(i,1,m) if(lft[a[i]]==i && rig[a[i]]==i) f[i][i]=1;
    	FOR(i,0,m) f[i+1][i]=1;
    	FOR(l,2,m) FOR(i,1,m-l+1){
    		int j=i+l-1,mn=i;
    		FOR(k,i+1,j) if(a[k]<a[mn]) mn=k;
    		int x=lft[a[mn]],y=rig[a[mn]],s1=0,s2=0,pre=0;
    		if(x<i || y>j) continue;
    		FOR(k,i,x) s1=(s1+1ll*f[i][k-1]*f[k][x-1])%mod;
    		FOR(k,y,j) s2=(s2+1ll*f[y+1][k]*f[k+1][j])%mod;
    		f[i][j]=1ll*s1*s2%mod;
    		FOR(k,i,j) if(a[k]==a[mn]){
    			if(pre) f[i][j]=1ll*f[i][j]*f[pre+1][k-1]%mod;
    			pre=k;
    		}
    	}
    	printf("%d
    ",f[1][m]);
    }
    
  • 相关阅读:
    JavaScript学习心得(六)
    JavaScript学习心得(五)
    JavaScript学习心得(四)
    JavaScript学习心得(三)
    JavaScript学习心得(二)
    JavaScript学习心得(一)
    socket异步接收信息
    DataTable将行转成列
    highcharts的柱状图边线
    w3cSchool jquery学习
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11422919.html
Copyright © 2011-2022 走看看