zoukankan      html  css  js  c++  java
  • Nowcoder9984I.九峰与分割序列(线段树+DP)

    I.九峰与分割序列

    题意:

    给出一个序列,将其分割成若干个子区间。

    子区间的贡献为:若前一个子区间的长度大于k且该区间长度小于等于k,则贡献为区间和的两倍,否则贡献为区间和。

    求一种分割方法,使得所有子区间贡献之和最大,输出最大贡献。

    题解:

    考虑DP。

    定义(f(i,0))表示最后一段区间大于k的最优解。

    定义(f(i,0))表示最后一段区间小于等于k的最优解。

    可以写出以下转移方程:

    (f(i,0)=max(f(i,0),max_{j=1}^{i-k-1}f(j,0)+sum_i-sum_j))

    (f(i,0)=max(f(i,0),max_{j=1}^{i-k-1}f(j,1)+sum_i-sum_j))

    (f(i,1)=max(f(i,1),max_{j=i-k}^{i-1}f(j,0)+sum_i*2-sum_j*2))

    (f(i,1)=max(f(i,1),max_{j=i-k}^{i-1}f(j,1)+sum_i-sum_j))

    这个转移方程看起来很难快速维护。

    有一个巧妙的思路,就是把和(j)有关的项合并,这样就可以用线段树维护了。

    开三棵线段树。

    第一棵维护(f(i,0)-sum_i)

    第二棵维护(f(i,1)-sum_i)

    第三棵维护(f(i,0)-sum_i*2)

    这样在转移的过程中,从对应的线段树里查询,最后再把每个状态更新到对应的线段树里就行了。

    // Problem: 九峰与分割序列
    // Contest: NowCoder
    // URL: https://ac.nowcoder.com/acm/contest/9984/I
    // Memory Limit: 524288 MB
    // Time Limit: 2000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    int n,k,a[maxn];
    
    struct node {
    	int i,l,r;
    	long long lazy,sum;
    }segTree[maxn<<2][3];
    void build (int i,int l,int r,int x) {
    	segTree[i][x].l=l;
    	segTree[i][x].r=r;
    	if (l==r) {
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(i<<1,l,mid,x);
    	build(i<<1|1,mid+1,r,x);
    }
    void spread (int i,int x) {
    	if (segTree[i][x].lazy) {
    		segTree[i<<1][x].sum+=segTree[i][x].lazy;
    		segTree[i<<1][x].lazy+=segTree[i][x].lazy;
    		segTree[i<<1|1][x].sum+=segTree[i][x].lazy;
    		segTree[i<<1|1][x].lazy+=segTree[i][x].lazy;
    		segTree[i][x].lazy=0;
    	}
    }
    void up (int i,int l,int r,long long v,int x) {
    	if (segTree[i][x].l>=l&&segTree[i][x].r<=r) {
    		segTree[i][x].sum+=v;
    		segTree[i][x].lazy+=v;
    		return;
    	}
    	spread(i,x);
    	int mid=(segTree[i][x].l+segTree[i][x].r)>>1;
    	if (l<=mid) up(i<<1,l,r,v,x);
    	if (r>mid) up(i<<1|1,l,r,v,x);
    	
    	segTree[i][x].sum=max(segTree[i<<1][x].sum,segTree[i<<1|1][x].sum);
    }
    long long query (int i,int l,int r,int x) {
    	if (l>r) return 0;
    	if (segTree[i][x].l>=l&&segTree[i][x].r<=r) {
    		return segTree[i][x].sum;
    	}
    	spread(i,x);
    	int mid=(segTree[i][x].l+segTree[i][x].r)>>1;
    	long long ans=-1e18;
    	if (l<=mid) ans=max(ans,query(i<<1,l,r,x));
    	if (r>mid) ans=max(ans,query(i<<1|1,l,r,x));
    	return ans;
    }
    long long sum[maxn];
    long long f[maxn][2];
    int main () {
    	scanf("%d%d",&n,&k);
    	for (int i=1;i<=n;i++) scanf("%d",a+i),sum[i]=sum[i-1]+a[i],f[i][0]=f[i][1]=-1e18;
    	//考虑DP
    	//f(i,0)表示最后一段区间大于k的最优解
    	//f(i,1)表示最后一段区间小于等于k的最优解
    	//f(i,0)=max(f(i,0),[j=k~i-k-1]f(j,0)+sum(i)-sum(j)
    	//f(i,0)=max(f(i,0),[j=1~i-k-1]f(j,1)+sum(i)-sum(j)
    	//f(i,1)=max(f(i,1),[j=i-k~i-1]f(j,0)+sum(i)*2-sum(j)*2
    	//f(i,1)=max(f(i,1),[j=i-k~i-1]f(j,1)+sum(i)-sum(j)
    	//把和j有关的项合并,就可以用线段树维护了,比赛的时候怎么就没想到呢
    	//开3颗线段树
    	//第一棵维护f(i,0)-sum(i)
    	//第二棵维护f(i,1)-sum(j)
    	//第三颗维护f(i,0)-sum(j)*2
    	build(1,1,n,0);
    	build(1,1,n,1);
    	build(1,1,n,2);
    	for (int i=1;i<=n;i++) {
    		if (i<=k) {
    			f[i][1]=sum[i];
    			up(1,i,i,f[i][1]-sum[i],1);
    			up(1,i,i,f[i][0]-sum[i],0);
    			up(1,i,i,f[i][0]-sum[i]*2,2);
    		}
    		else {
    			 f[i][0]=max(f[i][0],query(1,1,i-k-1,0)+sum[i]);
    			 f[i][0]=max(f[i][0],query(1,1,i-k-1,1)+sum[i]);
    			 f[i][1]=max(f[i][1],query(1,i-k,i-1,2)+sum[i]*2);
    			 f[i][1]=max(f[i][1],query(1,i-k,i-1,1)+sum[i]);
     			
    			 up(1,i,i,f[i][0]-sum[i],0);
    			 up(1,i,i,f[i][1]-sum[i],1);
    			 up(1,i,i,f[i][0]-sum[i]*2,2);
    		}
    	}
    	printf("%lld
    ",max(f[n][0],f[n][1]));
    }
    
  • 相关阅读:
    linux常用命令(二)文件上传下载及软件安装
    linux常用命令(一)linux开关机、重启以及文本界面与图形界面互换
    HTTP协议(一)基本概念、HTTP方法、HTTP状态码
    Martin Fowler 分层测试概念博文分享
    网络路由分析
    nginx 常见错误释义
    java解决共享资源竞争
    python操作excel及json
    一个简单的用python 实现系统登录的http接口服务实例
    Redis持久化之RDB&&AOF的区别
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14543858.html
Copyright © 2011-2022 走看看