【AtCoder】AGC006 Minimum Sum
阿新 • • 發佈:2018-12-13
文章目錄
題目
題目大意
給出一個的排列,求。
思路
題意就是求序列中每個區間的最小值之和。 考慮有多少個區間的最小值為,記為,則答案為: 若區間的最小值為,則其中的每一個數(除了)都比大。 直接說結論:
- 找到左邊離它最近的,滿足
- 找到右邊離它最近的,滿足
這樣找到的區間(注意是開的)是滿足最小值為的最大的一個區間。因為區間的最小值就不是了,是(),同理,區間的最小值一定是。 但是在區間和中的每個數都比大,從中選出一個作為左端點,中選出一個作為右端點,得到。
於是你發現,暴力完成這個結論還是的……
如果我們將比小的數的下標存在一個set<int> S
裡面,那麼l=S.lower_bound(i)
(實現的時候用lower_bound
好像會有神奇之事發生,詳見程式碼),r=S.upper_bound(i)
。
所以將排個序(和下標一塊,用結構體),然後順著掃,將前面的數都扔到set
裡面,再對的下標(排了序就不是了)找lower_bound
之類就可以了。
似乎有點像偏序……
反正這個問題我想了幾百年……
程式碼
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200000
int N;
struct node{
int val,ID;
}A[MAXN+5];
bool cmp(node x,node y){
return x.val<y.val;
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;i++){
A[i].ID=i;
scanf("%d",&A[i].val);
}
sort(A+1,A+N+1,cmp);
set<int> index;
index.insert(0),index.insert(N+1);//免得出現找不到的情況
long long Ans=0;
for(int i=1;i<=N;i++){
set<int>::iterator Left,Right;
Left=Right=index.upper_bound(A[i].ID),Left--;//注意Left的處理
Ans+=1ll*(A[i].ID-*Left)*(*Right-A[i].ID)*A[i].val;
index.insert(A[i].ID);
}
printf("%lld",Ans);
}