NOIP2018龍虎鬥,頗有感觸,一道除了long long別無他法的題(本人平生第一次發文章,多多包涵)
NOIP2018 龍虎鬥
時間限制: 1 Sec 記憶體限制: 256 MB
題目描述
軒軒和凱凱正在玩一款叫《龍虎鬥》的遊戲,遊戲的棋盤是一條線段,線段上有 n個兵營(自左至右編號 1 ~ n),相鄰編號的兵營之間相隔 1 釐米,即棋盤為長度為n − 1 釐米的線段。i號兵營裡有ci位工兵。
軒軒在左側,代表“龍”;凱凱在右側,代表“虎”。 他們以 m 號兵營作為分界,靠左的工兵屬於龍勢力,靠右的工兵屬於虎勢力,而第 m號兵營中的工兵很糾結,他們不屬於任何一方。
一個兵營的氣勢為:該兵營中的工兵數 × 該兵營到 m號兵營的距離;參與遊戲一方的勢力定義為:屬於這一方所有兵營的氣勢之和。
遊戲過程中,某一刻天降神兵,共有 s1 位工兵突然出現在了 p1 號兵營。作為軒軒和凱凱的朋友,你知道如果龍虎雙方氣勢差距太懸殊,軒軒和凱凱就不願意繼續玩下去了。為了讓遊戲繼續,你需要選擇一個兵營p2 ,並將你手裡的 s2 位工兵全部派往兵營 p2 ,使得雙方氣勢差距儘可能小。
注意:你手中的工兵落在哪個兵營,就和該兵營中其他工兵有相同的勢力歸屬(如果落在 m 號兵營,則不屬於任何勢力)。
輸入
輸入檔案的第一行包含一個正整數n,代表兵營的數量。
接下來的一行包含n個正整數,相鄰兩數之間以一個空格分隔,第i個正整數代
表編號為i的兵營中起始時的工兵數量 di 。
接下來的一行包含四個正整數,相鄰兩數間以一個空格分隔,分別代表m,p1 ,s1 ,s2 。
輸出
輸出檔案有一行,包含一個正整數,即 p2 ,表示你選擇的兵營編號。如果存在多個編號同時滿足最優,取最小的編號。
樣例輸入
(如果複製到控制檯無換行,可以先貼上到文字編輯器,再複製)
【輸入樣例 1】
6
2 3 2 3 2 3
4 6 5 2
【輸入樣例 2】
6
1 1 1 1 1 16
5 4 1 1
樣例輸出
【輸出樣例 1】
2
【輸出樣例 2】
1
提示
【輸入輸出樣例 1 說明】
雙方以 n = 4 號兵營分界,有 s1 = 5 位工兵突然出現在 p1 = 6 號兵營。
龍方的氣勢為:
2 × (4 − 1) + 3 × (4 − 2) + 2 × (4 − 3) = 14
虎方的氣勢為:
2 × (5 − 4) + (3 + 5) × (6 − 4) = 18
當你將手中的 s2 = 2 位工兵派往 p2 = 2 號兵營時,龍方的氣勢變為:
14 + 2 × (4 − 2) = 18
此時雙方氣勢相等。
【輸入輸出樣例 2 說明】
雙方以 n = 5 號兵營分界,有 s1 = 1 位工兵突然出現在 p1 = 4 號兵營。
龍方的氣勢為:
1 × (5 − 1) + 1 × (5 − 2) + 1 × (5 − 3) + (1 + 1) × (5 − 4) = 11
虎方的氣勢為:
16 × (6 − 5) = 16
當你將手中的 s2 = 1 位工兵派往 p2 = 1 號兵營時,龍方的氣勢變為:
11 + 1 × (5 − 1) = 15
此時可以使雙方氣勢的差距最小。
【資料規模與約定】
1 < m < n,1 ≤ p1 ≤ n。
對於20%的資料,n = 3, m = 2, ci = 1, s1,s2 ≤ 100。
另有20%的資料, n ≤ 10, p1 = m, ci = 1, s1,s2 ≤ 100。
對於20%的資料,n = 3, m = 2, ci = 1,s1,s2 ≤ 100。
對於60%的資料, n ≤ 100, ci = 1,s1,s2 ≤ 100。
對於80%的資料, n ≤ 100, ci,s1,s2 ≤ 100。
對於100%的資料, n ≤ 10^5, ci = 1, s1,s2 ≤ 10^9。
附上詳盡程式碼
/* 思路:
本題直接採用統計加暴枚思想便可AC
主要注意資料範圍以及模擬方法
採用差值比較法 , 節約時間並簡化過程 ( 虎的氣勢與龍的氣勢的差 )
*/
#include <cstdio>
long long N = 0 , M = 0 , P1 = 0 , Ans = 0 , C [ 100005 ] = { } , S1 = 0 , S2 = 0 , Sum = 0 , Minn = 1LL << 62;
//比賽必須初始化
//N : 兵營數量
//M : 中立兵營編號
//P1 : 天降神兵的兵營編號
//C : 每個兵營的士兵數量
//S1 : 天降神兵的數量
//S2 : "我"手裡有的兵
//Sum : 虎的氣勢與龍的氣勢的差
//Minn : 用於算出最小的氣勢 ( 相當於 2 的 62 次方 )
//讀入優化
void Read ( long long &X )// '&' 表示引用 , 在函式中改變了 X 的值就意味著在外面 X 的值也會被改變
{
int F = 1;//標記正負 , 用於負數的輸入
X = 0;//歸零 , 有可能傳進來時 X 沒有歸零
char S = getchar ( );//開始讀入
while ( S < '0' || S > '9' )//不是數字字元
{
if ( S == '-' )//不能直接把 F = -1 , 有可能輸入的不是 '-' 而是其他數字字元
{
F = ( ~ F ) + 1;//這個數是負數則改變 F , 出去時就能正確判斷正負
}
S = getchar ( );//繼續讀
}
while ( S >= '0' && S <= '9' )//是數字字元
{
X = ( X << 3 ) + ( X << 1 ) + S - 48;//每讀一位 * 10 , 為後一位留位置
S = getchar ( );//繼續讀
}
X *= F;//改變正負
}
void Print ( int X ) // 輸出優化
{
if ( X < 0 ) //如果 X 是負數
{
X = ( ~ X ) + 1;//將 X 變為 正數
putchar ( '-' );//輸出 '-' 號
}
if ( X > 9 )//如果 X 不能一次輸出 ( 因為putchar一次只能輸出一位 )
{
Print ( X / 10 );//先輸出最後一位前面的數 ( 如果前面的數 > 10 也可以通過這個遞迴輸出 )
}
putchar ( X % 10 + 48 );//輸出個位 ( 加上 48 才變為字元 )
}
int main()
{
//freopen ( "fight.in" , "r" , stdin );//比賽不能加上註釋
//freopen ( "fight.out" , "w" , stdout );//比賽不能加上註釋
Read ( N );//輸入 N , 兵營數量
for ( int I = 1 ; I <= N ; I ++ )//迴圈輸入 C [ I ] , 每個兵營的士兵數量
{
Read ( C [ I ] );
}
Read ( M );//輸入 M , 中立兵營編號
Read ( P1 );//輸入 P1 , 天降神兵的兵營
Read ( S1 );//輸入 S1 , 天降神兵的數量
Read ( S2 );//輸入 S2 , "我"手裡有的兵
C [ P1 ] += S1; // 初始化 C [ P1 ] , 既增加 S1 個士兵
for ( int I = 1 ; I <= N ; I ++ )//迴圈統計虎的氣勢與龍的氣勢的差
{
Sum += ( I - M ) * C [ I ];
}
for ( int I = 1 ; I <= N ; I ++ )//迴圈列舉每一個兵營
{
long long Now = Sum + ( I - M ) * S2;//把將兵派到這個兵營後虎的氣勢與龍的氣勢的差算出
if ( Now < 0 )//如果虎的氣勢與龍的氣勢的差小於零
{
Now = ( ~ Now );//將它變成正數方便比較 ( 因為最小差是虎的氣勢與龍的氣勢的差的絕對值 )
}
if ( Now < Minn )//尋找最優的軍營
{
Minn = Now;//改變最小值方便下次比較
Ans = I;//儲存答案
}
}
Print ( Ans );//輸出結果 , 即兵營編號
return 0;//比賽必加
}
//作為本次NOIP的第二道題,不算很難,但是long long真的沒有想到
//最為一名本次NOIP成功退役的人,這道題我只拿了80分
//所以資料範圍真的很重要啊,坑壞了不少人