[動態規劃]ACM預選賽F題 俠客行
這道題是我覺的這次預選賽中題目最難的一道,比賽過程中我並沒有做出來。
這種動態規劃的思路太巧秒了,我是想不到的。
再一次膜拜jxy學長
描述
眾所周知,龍島主和木島主發現了俠客島上的武功祕訣,這武功祕訣是李白《俠客行》的圖解,含義極是深奧繁複。他二人修習數月後,忽對圖解中所示武功產生了歧見。二人相互辯難剖析,鑽研其中道理,然終不能解。於是廣邀天下奇才異能之士同來島上,各竭心思,一起參研。恰好其時島上的“斷腸蝕骨腐心草”開花,此草若再配以其他佐使之藥,熬成熱粥,服後於練武之士大有裨益。於是派出使者,邀請當世名門大派的掌門人、各教教主、各幫幫主到俠客島喝碗臘八粥,再請他們去參研圖解。現有許多人到了俠客島,他們決定先進行一番較量,當然了,點到為止。
現有n個人排成一行,編號為1…n,每個人的內力為ai。
對於每兩個人(這兩個人可以是同一個人),這兩個人及其之間的所有人進行一次較量,勝者為他們中內力最大者。求所有比賽中勝者內力和。
如果這場比賽只有一個人的話,他本身就是獲勝者。
輸入
第一行包含一個整數 T (0<T<=1000)表示有 T 組測試資料
對於每組資料輸入格式如下:
第一行為一個整數n (1<n<=100000)表示人的數量。
第二行為n個整數ai,(0<ai<10^9),表示第i個人的內力。
資料保證n的總和不超過10^6。(資料加強了,請用 long long)
輸出
輸出一個整數,為所有比賽中勝者內力和
輸入樣例
2
4
1 2 3 4
5
2 3 1 4 2
輸出樣例
30
49
提示
Sample1
(max(1)+max(2)+max(3)+max(4)) + (max(1,2)+max(2,3)+max(3,4)) + (max(1,2,3)+max(2,3,4)) +(max(1,2,3,4))
=(1+2+3+4) + (2+3+4) + (3+4) +4
Sample2
(2+3+1+4+2) + (3+3+4+4) + (3+4+4) + (4+4) + (4)
題解
這道題目讓我們求出在所有任意區間中最大值的和
題目資料量很大隻能用 O(n)左右的演算法
一下程式碼是學長的,我複寫了一遍 加了幾行註釋 希望可以幫忙理解
//膜拜出題人大佬
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
const LL maxa = 1e11;
const int maxn = 1e6 + 10;
LL a[maxn];
LL sum[maxn];
int p[maxn];//指向第i個人從左依次數第一個比他能力強的人
int main(){
int t;
cin >> t;
while(t--){
LL ans = 0;
int n;
scanf("%d", &n);
scanf("%d", &a[1]);
sum[0] = p[1] = p[0] = 0;
a[0] = maxa, ans = sum[1] = a[1];
for(int i = 2; i <= n; i++){
scanf("%d", &a[i]);
p[i] = i - 1;
while(a[p[i]] <= a[i])
p[i] = p[p[i]];
sum[i] = sum[p[i]] + a[i]*(i - p[i]);
//這第i個人從左依次數第一個比他能力強的人 在他左邊區間勝的場數和帶上第i個人的區間勝的場數一樣多
//所以只用p[i]指向左邊比他大的人,真的妙
ans += sum[i];
}
cout << ans << "\n";
}
return 0;
}