P9742 「KDOI-06-J」贡献系统 题解
前言
其实这道题的难度真的不高,但是比赛时蒟蒻也是花费了一个小时才想出来,主要考查思维能力和熟练运用基本语法、基础算法的能力。
博客食用更佳
解题思路
这道题要求我们求出在排名变动后能够获得的最大贡献值,那么,我们很容易能够想到,如果有若干个人的排名上升,那么肯定会有至少一人的排名会下降,且这些排名下降的人,在比赛前的排名中,肯定是比排名上升的人靠前的,反之亦然。也就是说,
因为存在
-
在比赛开始前的排名最后一位的贡献值为正,那么也就说 对于所有的贡献为正的人,必然存在一种方案使得他们的排名下降,而对于那些在贡献为负的人排名后的人,必然存在一种方案使得他们的排名上升,那么,我们只需要找到第一个排名为负的人,把排名在他后面的所有人的贡献的绝对值相加就可以了。
-
在比赛开始前的排名最后一位的贡献值为负,那么这个时候我们就需要考虑一下是让哪一个贡献为负的人排名上升。因此,我们需要先找到从后往前数第一个贡献不为负的人,显然,从这个人开始,所有贡献为负的人的排名都可以下降,所有贡献为非负数的人的排名都可以上升。接着,我们计算从最后一个人到这个人的贡献值的绝对值的后缀和,然后枚举从第
个人到当前的这个人,每一个人排名上升所能增加的贡献值 ,易得, ,其中 表示从后往前数第一个贡献不为负的人的编号,那么我们可以求出后面这一段(从第一个贡献为负的人到最后一个人)的贡献最大值
在处理完后面这一段之后,我们还需要求出前面连续的一段贡献值为正的人的最大贡献值之和,和求
最后,我们的答案
AC 代码
#include<bits/stdc++.h>
#define ll long long
#define ull usigned long long
using namespace std;
const string TypideName="c";
inline void readc(char &c){
c=getchar();
while(c==' '||c=='\n')
c=getchar();
}inline void writec(char c){putchar(c);}
template<typename T>inline void read(T& x) {
if(typeid(x).name()==TypideName){char ch;readc(ch);x=ch;return;}
x = 0; bool f = false; char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') f = !f; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
x = (f ? -x : x); return;
}template<typename T>inline void put(T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) put(x / 10);
putchar(x % 10 + '0'); return;
}template<typename T>inline void write(T x) {
if(typeid(x).name()==TypideName){writec(x);return;}
put(x);
}
inline void read(__int128 &x){
x=0;bool f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=!f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
x=(f?x:-x);
}inline void put(__int128 x){
if(x<0) putchar('-'),x=-x;
if(x>9) put(x/10);
putchar(x%10+'0');return;
}inline void write(__int128 x){put(x);putchar('\n');}
template<typename T,typename... Args>
inline void read(T& x,Args&...x_) {read(x),read(x_...);}
template<typename T,typename... Args>
inline void write(T x,Args...x_){write(x),write(x_...);}
#define N 200005
int n;
struct OI{
ll r,c;
int pos;
}a[N],f[N],z[N];
int cntf,cntz;
ll mint[N],ans=0;
ll sumf[N],sum[N];
inline void work(){
read(n);cntf=cntz=ans=0;
for(int i=1;i<=n;i++)
read(a[i].r);
for(int i=1;i<=n;i++)
read(a[i].c);
for(int i=1;i<=n;i++)
a[i].pos=i;
for(int i=1;i<=n;i++)
if(a[i].c<0)
f[++cntf]=a[i];
if(f[cntf].pos==n){
int now=0;
for(int i=n;i>=1;i--)
if(a[i].c>=0){
now=i;break;
}
for(int i=f[1].pos;i<=now;i++)
ans+=abs(a[i].c);
memset(sumf,0,sizeof(sumf));
for(int i=n;i>now;i--)
sumf[i]=sumf[i+1]-a[i].c;
ll maxt=0;for(int i=n;i>now;i--)
if(sumf[now+1]-sumf[i]+a[i].c>maxt)
maxt=sumf[now+1]-sumf[i]+a[i].c;
ans+=maxt;
}else if(cntf>0)
for(int i=f[1].pos;i<=n;i++)
ans+=abs(a[i].c);
int now=f[1].pos-1;
if(cntf==0) now=n;
memset(sum,0,sizeof(sum));
for(int i=1;i<=now;i++)
sum[i]=sum[i-1]+a[i].c;
ll maxt=0;
for(int i=1;i<now;i++){
if(sum[now]-sum[i]-a[i].c>maxt)
maxt=sum[now]-sum[i]-a[i].c;
}ans+=maxt;
write(ans,'\n');
}
signed main(){
int T;read(T);
while(T--)work();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下