题目地址


 易错点:

  • abs()在开long long时必须重写.
  • 在答案相同时优先选择编号较小的.
  • 开long long.

#include<cstdio>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const int MAXN=5e6;
ll c[MAXN];//兵营的原始兵量 
ll m,n;
ll getASum(){//获取A阵营的总气势 
	ll ASum=0;
	for(int i=1;i<=m-1;i++){
		ASum+=c[i]*abs(m-i);
	}
	return ASum;
}
ll getBSum(){//获取B阵营的总气势 
	ll BSum=0;
	for(int i=m+1;i<=n;i++){
		BSum+=c[i]*abs(m-i);
	}
	return BSum;
}
bool isFromA(ll x){//判断是否属于A阵营 
	return (x<m);
}
ll absK(ll val){
	if(val>=0)return val;
	return -val;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>c[i];
	}
	//中立势力 
	//免费赠送兵位置 数量 
	int p1,s1,
	s2;//自己的兵量 
	cin>>m>>p1>>s1>>s2;
	c[p1]+=s1;//免费送兵 
	ll Asum=0,Bsum=0;//两个阵营的总气势 
	Asum=getASum(),Bsum=getBSum();
	ll ansIndex,ansDelta;//当前位置和当前气势差值
	ansIndex=m,ansDelta=absK(Asum-Bsum);
	for(int i=1;i<=n;i++){//尝试在每个兵营加气势
		if(i==m)continue; 
		bool isA=isFromA(i);//是否属于A阵营
		if(isA){//如果属于A阵营
			ll newAsum=Asum+s2*absK(m-i);//A阵营新总值
			ll newDelta=absK(newAsum-Bsum); 
			if(newDelta<ansDelta){//能更新 
				ansDelta=newDelta;
				ansIndex=i;
			}else if(newDelta==ansDelta&&i<ansIndex){
				ansIndex=i;
			}
		}else{
			ll newBsum=Bsum+s2*absK(m-i);
			ll newDelta=absK(Asum-newBsum);
			if(newDelta<ansDelta){
				ansDelta=newDelta;
				ansIndex=i;
			}else if(newDelta==ansDelta&&i<ansIndex){
				ansIndex=i;
			}
		}
	}
	printf("%lld\n",ansIndex);
	return 0; 
}