题目大意:令ai={1,2,3,4,n},求一个排列b,使得贡献值最大,其中,当bi>ai时,获得贡献bi,bi=ai时,获得贡献为0,bi<ai时,获得贡献为-bi
思路:显然,如果放弃一个点,那么后面的点都是可行的,且这一点在第一个正数连续区间,因为负数区间或者其他正数区间都是一定可以取到的,负数区间去到后面,非第一个正数区间取在后面。
将这一思路扩展至最后一段的负数区间,同理
所以最终贡献为第一个正数区间的最大值,第一个负数区间的最大值(在数组末尾),和其他区间的贡献和,即
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;
}