P9742 「KDOI-06-J」贡献系统

题目大意:令ai={1,2,3,4,n},求一个排列b,使得贡献值最大,其中,当bi>ai时,获得贡献bi,bi=ai时,获得贡献为0,bi<ai时,获得贡献为-bi

思路:显然,如果放弃一个点,那么后面的点都是可行的,且这一点在第一个正数连续区间,因为负数区间或者其他正数区间都是一定可以取到的,负数区间去到后面,非第一个正数区间取在后面。

将这一思路扩展至最后一段的负数区间,同理

所以最终贡献为第一个正数区间的最大值,第一个负数区间的最大值(在数组末尾),和其他区间的贡献和,即ans1=-a[i]+\sum_{i}^{ed}     ans2=a[i]+\sum_{st}^{i-1}     ans3=\sum_{st+1}^{ed-1}

ans=ans1+ans2+ans3

#include<bits/stdc++.h>
#define int long long 
using namespace std;

const int N = 1e6 + 10;
int n,T,ans,s[N],a[N];

int cal(int l,int r){
	if(l>r)  return 0;
	else return s[r]-s[l-1];
}
signed main(){
	ios::sync_with_stdio(false);
	cin>>T;
	while(T--){
		ans=0;
		cin>>n;
		memset(s,0,sizeof s);
		for(int i=1,x;i<=n;i++)  cin>>x;
		for(int i=1,x;i<=n;i++){
			cin>>a[i];
			s[i]=s[i-1]+abs(a[i]);	
		}  
		int st1,ed1,st2,ed2;
		st1=ed1=st2=ed2=0;
		for(int i=1;i<=n;i++){
			if(a[i]>=0&&i==1)  st1=1;
			if(a[i]<0){
				ed1=i-1;
				break;
			}
			if(i==n)  ed1=i;
		}
		for(int i=n;i>=1;i--){
			if(a[i]<0&&i==n)  ed2=n;
			if(a[i]>=0){
				st2=i+1;
				break;
			}  
			if(i==1)  st2=i;
		}
		if(st1&&ed1){
			int sum=0;
			for(int i=1;i<ed1;i++)
		       sum=max(sum,-a[i]+cal(i+1,ed1));
		    ans+=sum;
		} 
		if(st2&&ed2){
			int sum=0;
			for(int i=ed2;i>st2;i--)
			  sum=max(sum,a[i]+cal(st2,i-1));
			ans+=sum;
		}
		//cout<<ed1<<" "<<st2<<" "<<ans<<endl;
	    ans+=cal(ed1+1,st2-1);
	    cout<<ans<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值