题目链接
题解链接
ps:此篇博客是对题解的个人理解,为了使以后看到这道题可以看懂,如果原作者认为此篇博客侵权了,请联系我删除
题解原文:
个人理解:
解释一:
首先来个图:
很容易发现,如果要按最小步骤得到的最大值,那么一定是如下的图:
操作次序为:红(1次),橙(3次),黄(1次),绿(3次)
从这里我们就可以发现结论:前括号划分的位置恰好都是在差分(
a
[
i
+
1
]
−
a
[
i
]
a[i + 1] - a[i]
a[i+1]−a[i])为正的位置,后括号划分的位置恰好都是在差分为负的位置
而按最小步骤得到的最大值则需各位自己画图理解(ps:可以发现括号的位置都是一样的,但是顺序却不同)
综上,(主要是题解 ),我们就可以大胆猜测要想用最小步骤得到代价最小值以及最大值,一定要满足上述结论
简单证明为啥这样是最少步骤且能得到最大值:
假设一个全不为0的序列,那么肯定一开始要对整个序列减一,如果一开始就不这样做,那么一定不会得到最优步骤,而且值肯定也会变小…(这只是粗略证明,详细证明,我好像并不会…)
至于为啥这样是最少步骤这样也能得到最小值,请自证(真是令人讨厌的词汇 )
解释二:
-
假设已经求出所有括号的位置,即ai, bi那么根据题意,就能得到上图那个式子,再将其简单转换一下,得到如上等式
-
根据我们小学二年级学的排序不等式,如果想求 r e s res res最大那么一定要满足
其次再满足
就能得到res的最大值
通俗来讲就是:最远的那个后括号要与最前面的前括号对应 -
r e s res res最小,请自证
解释三:
为啥最大值要用栈来维护a呢? -
因为栈是先进后出,所以能保证:最远的那个后括号要与最前面的前括号对应
同理可证为啥最小值要用队列维护a
AC代码:
// Test1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
typedef pair <ll, ll> pi;
const int maxn = 500100;
const ll Mod = 1000000007;
ll a[maxn], res1, res2, n;
stack <pi> sta;//计算最大值
queue <pi> que;//计算最小值
int main() {
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
a[0] = a[n + 1] = 0;
//算最小值
for (int i = 0; i <= n; i++) {
if (a[i + 1] - a[i] > 0) que.push(pi(i, a[i + 1] - a[i]));//前括号,队列维护
else if (a[i + 1] - a[i] < 0) {//后括号
ll tmp = a[i] - a[i + 1];
while (tmp && que.front().second <= tmp) {
res1 += que.front().second * (i - que.front().first) % Mod * (i - que.front().first) % Mod;
res1 %= Mod;
tmp -= que.front().second;
que.pop();
}
if (tmp) {//如果不能抵消了,那么就不会弹出
res1 += tmp * (i - que.front().first) % Mod * (i - que.front().first) % Mod;
res1 %= Mod;
que.front().second -= tmp;
}
}
}
//算最大值
for (int i = 0; i <= n; i++) {
if (a[i + 1] - a[i] > 0) sta.push(pi(i, a[i + 1] - a[i]));//栈维护
else if (a[i + 1] - a[i] < 0) {
ll tmp = a[i] - a[i + 1];
while (tmp && sta.top().second <= tmp) {
res2 += sta.top().second * (i - sta.top().first) % Mod * (i - sta.top().first) % Mod;
res2 %= Mod;
tmp -= sta.top().second;
sta.pop();
}
if (tmp) {
res2 += tmp * (i - sta.top().first) % Mod * (i - sta.top().first) % Mod;
res2 %= Mod;
sta.top().second -= tmp;
}
}
}
cout << res1 << " " << res2 << endl;
return 0;
}