• 题解「BZOJ4621 Tc605」


    可以发现,每次操作事实上是一次推平。而取最大值的限制则限定了每个值能够推平的最大区间,记 (a_i) 能够推平到最左的位置为 (l_i),能够推平到最右的位置为 (r_i)

    那么问题转化为用 (m) 个区间覆盖整个序列,但可以有长度为 (1) 的段不被覆盖(其实就是单点)

    (f_{i,j}) 为使用了 (j) 个区间覆盖 (1sim i),直接转移不太方便,刷表转移即可。枚举每个 (i),对于所有的 (l_ileq kleq r_i),将 (f_{k,j}) 加上 (sumlimits_{x=l_i-1}^{k-1} f_{k,j-1})。直接转移总时间复杂度是 (O(n^4)) 的,观察到右端点 (k-1) 单调增,前缀和优化即可。另外,值得注意的是,单点的情况会被覆盖两次,需要减去一次。

    由于单点不一定要被覆盖,所以会出现用 (0sim m) 段区间覆盖整个序列的情况,都要统计进答案内。

    #include<cstdio>
    const int mod=1e9+7;
    int f[505][505],a[505];
    inline int read() {
    	register int x=0,f=1;register char s=getchar();
    	while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    	return x*f;
    }
    int main() {
    	int n=read(),m=read(),ans=0;
    	for(register int i=1;i<=n;++i) a[i]=read(); f[0][0]=1;
    	for(register int i=1;i<=n;++i) {
    		int L=i-1,R=i+1; while(L>=1&&a[L]<a[i]) --L; while(R<=n&&a[R]<a[i]) ++R;
    		for(register int j=m;j>=0;--j) {
    			f[i][j]=(f[i][j]+f[i-1][j])%mod;
    			if(j) {
    				for(register int k=L+1,sum=0;k<=R-1;++k) {sum=(sum+f[k-1][j-1])%mod; f[k][j]=(f[k][j]+sum)%mod;}
    				f[i][j]=(f[i][j]-f[i-1][j-1]+mod)%mod;
    			}
    		}
    	}
    	for(register int i=0;i<=m;++i) ans=(ans+f[n][i])%mod; printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    OpenCV——Skewing
    OpenCV——PS滤镜算法之Spherize 球面化(凸出效果)
    机器学习 scikit-learn 图谱
    机器视觉 Histogram of oriented gradients
    Python: scikit-image canny 边缘检测
    机器视觉 Local Binary Pattern (LBP)
    Ice php配置
    Windows7下的免费虚拟机(微软官方虚拟机)
    经常使用的webservice接口
    怎样衡量一个公司是否靠谱
  • 原文地址:https://www.cnblogs.com/tommy0103/p/13842176.html
Copyright © 2020-2023  润新知