题目描述

轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有nn 个兵营(自左至右编号1n1∼n),相邻编号的兵营之间相隔11厘米,即棋盘为长度为n1n-1厘米的线段。ii号兵营里有cic_i位工兵。 下面图11n=6n=6的示例:【NOIP2018普及组】龙虎斗
轩轩在左侧,代表“龙”;凯凯在右侧,代表“虎”。 他们以mm号兵营作为分界, 靠左的工兵属于龙势力,靠右的工兵属于虎势力,而第mm号兵营中的工兵很纠结,他们不属于任何一方。
一个兵营的气势为:该兵营中的工兵数 × 该兵营到mm号兵营的距离;参与游戏 一方的势力定义为:属于这一方所有兵营的气势之和。
下面图22n=6n=6,m=4m = 4的示例,其中红色为龙方,黄色为虎方:
【NOIP2018普及组】龙虎斗
游戏过程中,某一刻天降神兵,共有s1s_1位工兵突然出现在了p1p_1号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营p2p_2,并将你手里的s2s_2位工兵全部派往兵营p2p_2,使得双方气势差距尽可能小。

注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在mm号兵营,则不属于任何势力)。

输入输出格式

输入格式:

输入文件的第一行包含一个正整数nn,代表兵营的数量。接下来的一行包含nn个正整数,相邻两数之间以一个空格分隔,第ii个正整数代 表编号为ii的兵营中起始时的工兵数量cic_i。接下来的一行包含四个正整数,相邻两数间以一个空格分隔,分别代表mm,p1p_1,s1s_1,s2s_2

输出格式:

输出文件有一行,包含一个正整数,即p2p_2,表示你选择的兵营编号。如果存在多个编号同时满足最优,取最小的编号。

输入输出样例

输入样例#1:
6 
2 3 2 3 2 3 
4 6 5 2 
输出样例#1:
2
输入样例#2:
6 
1 1 1 1 1 16 
5 4 1 1
输出样例#2:
1

说明

输入输出样例 1 说明】

见问题描述中的图22
双方以m=4m=4号兵营分界,有s1=5s_1=5位工兵突然出现在p1=6p_1=6号兵营。 龙方的气势为:

2×(41)+3×(42)+2×(43)=142×(4−1)+3×(4−2)+2×(4−3)=14

虎方的气势为:

2×(54)+(3+5)×(64)=182×(5−4)+(3+5)×(6−4)=18

当你将手中的 s2=2s_2=2位工兵派往p2=2p_2=2号兵营时,龙方的气势变为:

14+2×(42)=1814+2×(4−2)=18

此时双方气势相等。

【输入输出样例 2 说明】

双方以m=5m=5号兵营分界,有s1=1s_1=1位工兵突然出现在p1=4p_1 =4号兵营。
龙方的气势为:

1×(51)+1×(52)+1×(53)+(1+1)×(54)=111×(5−1)+1×(5−2)+1×(5−3)+(1+1)×(5−4)=11

虎方的气势为:

16×(65)=1616×(6−5)=16

当你将手中的s2=1s_2=1位工兵派往p2=1p_2=1号兵营时,龙方的气势变为:

11+1×(51)=1511+1×(5−1)=15

此时可以使双方气势的差距最小。

【数据规模与约定】
1<m<n,1p1n1<m<n,1≤p_1≤n
对于20%20\%的数据,n=3,m=2,ci=1,s1,s2100n=3,m=2,c_i=1,s_1,s_2≤100
另有20%20\%的数据,n10,p1=m,ci=1,s1,s2100n≤10,p_1=m,c_i=1,s_1,s_2≤100
对于60%60\%的数据,n100,ci=1,s1,s2100n≤100,c_i=1,s_1,s_2≤100
对于80%80\%的数据,n100,ci,s1,s2100n≤100,c_i,s_1,s_2 ≤ 100
对于100%100\%的数据,n105,ci,s1,s2109n≤10^5 ,c_i,s_1,s_2≤10^9

思路

其实这一道题还是比较简单的。
读到这里应该已经有人握紧拳头了
因为mm是要后面读入的,所以我是读入完后再一个forfor语句算出llrr(ll带表左方的气势,rr带表右方的气势)(还有气势也可以用前缀和算,但当时没有想到),然后根据两个判断和公式即可求出。

#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,k,a[10000005];
int main()
{
// 	freopen("fight.in","r",stdin);
// 	freopen("fight.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)
        scanf("%lld",&a[i]);
    long long x,y;
    scanf("%lld%lld%lld%lld",&m,&x,&y,&k);
    if(m==1 || m==n)//因为都大于0,所以如果在1或n就可以直接输出m
    {
    	printf("%d",m);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    a[x]+=y;//把后来要加的加上
    long long l=0,r=0;
    for(int i=1;i<=n;++i)//算气势
    {
        if(i<m)l+=(long long)a[i]*(m-i);
        else r+=(long long)a[i]*(i-m);
    }
    if(l<r)//如果右边的气势比左边大,把“救兵”放左边
    {
        long long t=m-((r-l)/k);//这个程序的精华
        if((r-l)%k>k/2)t--;//精华#2,因为要算最近的,所以一波骚操作
        printf("%lld",max(t,(long long)1));//防止超界
    }
    else 
    if(l>r)//如果左边的气势比右边大,把“救兵”放右边
    {
        long long t=m+((l-r)/k);//精华
        if((l-r)%k>k/2)t++;//精华#2
        printf("%lld",min(t,(long long)n));//防止超界
    }
    else
    if(l==r)printf("%lld",m);//如有两边气势相同,就放在分界点
// 	fclose(stdin);
// 	fclose(stdout);
    return 0;
}

相关文章: