「QFOI R2」鐘聲遠帶斜陽
題目描述
注意:本題中的所有數列下標從 \(0\) 開始。
小 R 是一個可愛的女孩子,她喜歡研究無窮數列。
她稱一個無窮數列 \(b\) 是美妙的,當且僅當存在自然數 \(k_0\),使得對於所有 \(k\ge k_0\),都滿足 \(b\) 中下標在區間 \([k_0,k]\) 內的所有數的和非負(即 \(\sum_{i=k_0}^kb_i\ge 0\))。例如,數列 \(\alpha_i=i-5\) 是美妙的,取 \(k_0=5\) 符合要求;但 \(\beta_i=-i\) 不是美妙的。
她目前只有一個長度為 \(n\) 的有窮數列 \(a\),可以進行任意次以下三種操作:
- 花費 \(p\) 的代價,選擇一個整數 \(i\)(\(0\le i < n\)),將 \(a_i\) 增加一。
- 花費 \(q\) 的代價,選擇一個整數 \(i\)(\(0\le i < n\)),將 \(a_i\) 刪除,同時更新 \(n\) 為新的數列長度。不能將數列刪空。
- 花費 \(r\) 的代價,選擇兩個整數 \(i,j\)(\(0\le i < j < n\)),交換 \(a_i\) 與 \(a_j\)。
她希望在若干次操作後,用無限個有窮數列 \(a\) 依次相接得到無窮數列 \(b\)(即 \(b_i=a_{i\bmod n}\)),使得 \(b\) 是美妙的。請你求出最小的代價。
輸入格式
第一行四個整數 \(n,p,q,r\)。
第二行 \(n\) 個整數,表示數列 \(a\)。
輸出格式
一行,一個整數,表示最小代價。
樣例 #1
樣例輸入 #1
5 1 2 5
2 -2 3 -3 -1
樣例輸出 #1
1
樣例 #2
樣例輸入 #2
5 2 1 5
2 -2 3 -3 -1
樣例輸出 #2
1
樣例 #3
樣例輸入 #3
5 1 1 1
0 1 2 3 4
樣例輸出 #3
0
提示
樣例 \(1\) 解釋
花費 \(p=1\) 的代價將 \(a_3\) 增加一,得到數列 \(b=[2,-2,3,-2,-1,2,-2,3,-2,-1,\cdots]\) 是美妙的,取 \(k_0=2\) 符合要求。
可以證明不存在代價更小的方案。
樣例 \(2\) 解釋
花費 \(q=1\) 的代價將 \(a_1\) 刪除,得到數列 \(b=[2,3,-3,-1,2,3,-3,-1,\cdots]\) 是美妙的,取 \(k_0=0\) 符合要求。
可以證明不存在代價更小的方案。
資料範圍
本題採用捆綁測試。只有透過子任務中所有測試點以及所有依賴的子任務,才能獲得相應的分數。
對於全部資料:\(1\le n\le 10^5\),\(1\le p,q,r\le 10^9\),\(|a_i|\le 10^9\)。
- 子任務一(\(10\) 分):\(n=1\)。
- 子任務二(\(10\) 分):\(n\le 10\)。依賴子任務一。
- 子任務三(\(20\) 分):\(|a_i|\le 1\)。
- 子任務四(\(20\) 分):\(\sum|a_i|\le 10^5\)。依賴子任務三。
- 子任務五(\(40\) 分):無特殊限制。依賴子任務一、二、三、四。
分析
轉化
轉化一下:有一個長為 $ n $ 的數字環,從某一個下標沿某個方向迴圈遍歷,遍歷過程中累加環上的數字,當且僅當任意時刻數字之和 $ sum \ge 0$ 稱其為美妙的。
因為 $ {b_i} $ 是無限長的,所以 $ S =\sum_{i=1}^n a_i $ 會不斷累加,此時只有 $ S $ 的正負性對總和正負性有影響, $ S \lt 0 $ 必然導致總和從某一位置開始小於零。
條件證明
由上,很容易得到一個符合定義的 $ {a_i} $ 的必要不充分條件: $ S \ge 0 $ 。
以下給出充分性證明:
$ \large 證明:\ $
即存在一個初始位置,使得前 $ n $ 步的 $ n $ 個和均大於等於零。
不妨從 $ i $ 開始,破環為鏈,以 $ i $ 為起點遍歷 $ {a_i} $ ,對於 $ x_0 $ 有兩種情況:
-
$ \exist x_0 \le k \le n,\sum_{j=x_0}^k a_j \lt 0 $ 此時找到第一個總和小於零的區間,劃分出來,將總和歸零從 $ k $ 下一位開始走。
-
$\forall x_0 \le k \le n,\sum_{j=x_0}^k a_j \ge 0 $ 這個字尾區間是美妙的。
可以發現每次得到情況一,左側和的絕對值均小於等於右側的絕對值( $ S \ge 0$ ),在經過若干次劃分後必然存在一個字尾區間的和與左側所有數之和大於零且該字尾區間是美妙的。從這個下標 $ h $ 開始迴圈遍歷形成的 $ b_i $ 必然是美妙的。
所以操作三是無效的。只需考慮操作一和二,將原陣列排序後比較刪除和累加哪種更優,注意數列非空即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
long long n,p,q,r;
long long g[N],sum,ans;
int main()
{
scanf("%lld%lld%lld%lld",&n,&p,&q,&r);
for(int i=1;i<=n;++i){scanf("%lld",g+i);sum+=g[i];}
sort(g+1,g+1+n);
if(sum>=0){cout<<0;return 0;}
int tot=0;
for(int i=1;i<=n;++i)
{
if(g[i]>=0 || sum>=0){sum=0;break;}
if(q>min(-g[i],-sum)*p)
{
ans+=min(-g[i],-sum)*p;
sum+=min(-sum,-g[i]);
}
else
{
if(tot==n-1)break;
++tot;
ans+=q;
sum-=g[i];
}
}
if(sum<0)
{
if(tot<n-1)
ans+=(-sum*p,q);
else
ans+=-sum*p;
}
cout<<ans;
return 0;
}