zoukankan      html  css  js  c++  java
  • 51Nod 1052/1053/1115 最大M子段和V1/V2/V3

    V1

    N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M >= N个数中正数的个数,那么输出所有正数的和。N,M<=5000
    例如:-2 11 -4 13 -5 -2,分为2段,11 -4 13一段,6一段,和为26。

    V2

    N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M >= N个数中正数的个数,那么输出所有正数的和。 N,M<=50000
    例如:-2 11 -4 13 -5 6 -2,分为2段,11 -4 13一段,6一段,和为26。
    V3
    环形最大M子段和,N个整数组成的序列排成一个环,a[1],a[2],a[3],…,a[n]( a[n], a[1]也可以算作1段),将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M>=N个数中正数的个数,那么输出所有正数的和。N,M<=100000
    例如:-2 11 -4 13 -5 6 -1,分为2段,6 -1 -2 11一段,13一段,和为27。

    这三道题非常类似可以用几乎同一个code过掉

    我们直接先考虑V3比较好做

    首先将所有连续且符号相同的数加在一起,那么我们得到一个正负交替的环

    如果不考虑限制,显然取所有正数最优

    现在考虑限制,我们假设环上正数c个

    那么就要减少M-c段,考虑减少段数的手段

    1.删去一段

    2.将两端合并成为一段

    这个时候发现问题可以转化为经典的种花问题:

    将所有的正数变为负数,在N个数(全部为负)中选出M-c个最大的,而相邻的不能选

    选出来的数加上原本所有正数的和就是答案

    直接套用原来的可撤销贪心做法就可以了,v2就多加一个权值为-∞的0号节点即可

    V2code

    #pragma GCC opitmize("O3")
    #pragma G++ opitmize("O3")
    #include<queue>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 50010
    using namespace std;
    int n,m,t=0,l[N],r[N]; long long S=0,s[N],v[N];
    priority_queue<pair<long long,int> > q; bool vis[N]={0};
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		scanf("%lld",v+i);
    		if(!t && v[i]<0) continue; else
    		if(!t || (v[i]>=0)!=(s[t]>=0)) s[++t]=v[i]; else s[t]+=v[i];
    	}
    	while(s[t]<0) s[t--]=0;
    	for(int i=1;i<=t;++i){
    		l[i]=i-1; r[i]=i+1;
    		if(i&1){
    			S+=s[i]; s[i]=-s[i];
    			q.push(make_pair(s[i],i));
    		} else q.push(make_pair(s[i],i));
    	}
    	r[t]=0; l[0]=t; r[0]=1;
    	q.push(make_pair(s[0]=-1000000000000ll,0));
    	if(m>(t>>1)) return 0&printf("%lld
    ",S);
    	pair<long long,int> x; int y;
    	for(m=(t-(t>>1))-m;m--;){
    		x=q.top(); q.pop();
    		if(vis[y=x.second]){++m; continue;}
    		else{
    			S+=s[y]; s[y]=-s[y]+s[l[y]]+s[r[y]];
    			q.push(make_pair(s[y],y));
    			r[l[l[y]]]=y;
    			l[r[r[y]]]=y;
    			vis[l[y]]=1;
    			vis[r[y]]=1;
    			l[y]=l[l[y]];
    			r[y]=r[r[y]];
    		}
    	}
    	printf("%lld
    ",max(0ll,S));
    }
    V3code

    #pragma GCC opitmize("O3")
    #pragma G++ opitmize("O3")
    #include<queue>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 200010
    using namespace std;
    int n,m,t=0,l[N],r[N],c; long long S=0,s[N],v[N];
    priority_queue<pair<long long,int> > q; bool vis[N]={0};
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		scanf("%lld",v+i);
    		if(!t || (v[i]>=0)!=(s[t]>=0)) s[++t]=v[i]; else s[t]+=v[i];
    	}
    	if((s[1]>=0)==(s[t]>=0)) s[1]+=s[t--];
    	for(int i=1;i<=t;++i){
    		l[i]=i-1; r[i]=i+1;
    		if(s[i]>=0){
    			S+=s[i]; s[i]=-s[i]; c++;
    			q.push(make_pair(s[i],i));
    		} else q.push(make_pair(s[i],i));
    	}
    	r[t]=1; l[1]=t;
    	if(m>=c) return 0&printf("%lld
    ",S);
    	pair<long long,int> x; int y;
    	for(m=c-m;m--;){
    		x=q.top(); q.pop();
    		if(vis[y=x.second]){++m; continue;}
    		else{
    			S+=s[y]; s[y]=-s[y]+s[l[y]]+s[r[y]];
    			q.push(make_pair(s[y],y));
    			r[l[l[y]]]=y;
    			l[r[r[y]]]=y;
    			vis[l[y]]=1;
    			vis[r[y]]=1;
    			l[y]=l[l[y]];
    			r[y]=r[r[y]];
    		}
    	}
    	printf("%lld
    ",max(0ll,S));
    }


  • 相关阅读:
    HDU1720 A+B Coming
    HDU1390 ZOJ1383 Binary Numbers
    HDU1390 ZOJ1383 Binary Numbers
    HDU2504 又见GCD
    HDU2504 又见GCD
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1020 ZOJ2478 Encoding
    HDU1020 ZOJ2478 Encoding
    HDU2097 Sky数
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477128.html
Copyright © 2011-2022 走看看