zoukankan      html  css  js  c++  java
  • 题解「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;
    }
    
  • 相关阅读:
    linux 下查看目录所占用空间大小 du命令功能
    nginx 的启动 停止和重启
    excel vba
    过程中遇到的问题
    Java python BDA文件上传下载项目遇到的问题
    java login小方法集合
    python 初学
    python 从0学起
    python交互的几种方式
    模块与包概念与调用
  • 原文地址:https://www.cnblogs.com/tommy0103/p/13842176.html
Copyright © 2011-2022 走看看