这道题是我觉的这次预选赛中题目最难的一道,比赛过程中我并没有做出来。
这种动态规划的思路太巧秒了,我是想不到的。
再一次膜拜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;
}