D. Riverside Curio

D. Riverside Curio

​ https://codeforces.com/problemset/problem/957/D

Arkady decides to observe a river for n consecutive days. The river’s water level on each day is equal to some real value.

Arkady goes to the riverside each day and makes a mark on the side of the channel at the height of the water level, but if it coincides with a mark made before, no new mark is created. The water does not wash the marks away. Arkady writes down the number of marks strictly above the water level each day, on the i-th day this value is equal to mi.**

Define di as the number of marks strictly under the water level on the i-th day. You are to find out the minimum possible sum of di over all days. There are no marks on the channel before the first day.

Input

The first line contains a single positive integer n (1 ≤ n ≤ 105) — the number of days.

The second line contains n space-separated integers m1, m2, …, mn (0 ≤ mi < i) — the number of marks strictly above the water on each day.

Output

Output one single integer — the minimum possible sum of the number of marks strictly below the water level among all days.

Examples

input

6
0 1 0 3 0 2

output

6

input

5
0 1 2 1 2

output

1

input

5
0 1 1 2 2

output

0

Note

In the first example, the following figure shows an optimal case.

在这里插入图片描述

Note that on day 3, a new mark should be created because if not, there cannot be 3 marks above water on day 4. The total number of marks underwater is 0 + 0 + 2 + 0 + 3 + 1 = 6.

In the second example, the following figure shows an optimal case.

img

题意:

一个人每天去河边看水位,水的高度与之前不同就在这个高度做标记,如果这个高度已经标记过了就不做任何事,数组m有n个元素,m 1代表第一天来的时候,看到的水面上的标记,一定是0(因为第一天才开始标记),m 2代表第二天看到的水面上的标记(因为水位会变),以此类推。求所有天中严格低于水位的标记数目的最小和

分析:

难点主要是推式子,我们只要知道每天总共有多少个标记,和每天在水面上的标记数,相减再-1(减去刚好贴着水面的标记)就是在水面下的标记了,最后求和就是答案了。

设t[i]为第i天的划线数量,第一天为1,m[i]为第i天严格在上面的数,b[i]为第i天严格在下面的数,那么有
b [ i ] = t [ i ] − m [ i ] − 1 b[i] = t[i]-m[i]-1 b[i]=t[i]m[i]1
现在问题就是求b数组,也就是求在水面下的标记数(这里绝对是个难点)。

由一个例子,Day 1时m 1是0,此时标记数就是0+1=1(因为当天标记的是贴着水面的,所以要加一),Day 2时m 2是1,此时标记数就是1+1=2,但是到了Day 3,m 3就变成了0,因为这是水位突然猛涨,人家已经看不到之前的标记了,既然变成0了,那不就不知道第三天究竟有几个标记了吗?

确实不知道,但我们知道的是,此时的标记数不是2个就是3个。为什么?因为此时看不到标记,水位要么回到了之前的高度(标记贴着水面),要么高于之前的标记。我们要确定是2还是3,就得看后面。因为Day 4时看到了3个标记,所以Day 3的时候只能是3个标记,也就是说,水位上升的时候要看后面才能确定标记数。

先正向遍历一遍,水位下降时(m增大),我们可以确定有几个标记(m+1),水位上升到要标记新的标记时,就取昨天的标记数。合并到一起就是:

for(int i=1;i<=n;++i) t[i]=max(t[i-1],m[i]+1);

为了求水位上升时的标记数,需要再反向遍历一遍。

  for(int i=n-1;i>=1;--i)
	if(t[i+1]-t[i]>1)
		t[i]=t[i+1]-1;

注意,这里判断相邻两天标记数之差不能超过1,为什么?因为你每次来河边标记,要么不标记,要么就标记一次呀,所以两边最多只能相差1,且左边等于右边减1。为什么不是右边等于左边加1?前面已经说了,比如第三天的标记数不是2个就是3个,我们取了第二天的标记数(2),所以要让标记数尽量大,让左边大一点,而不是让右边小一点。

代码:
#include<iostream>
#include<algorithm>
#define int long long
#define Please return
#define AC 0
using namespace std;
const int N=1e6+1;
void fastio(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);}
int a[N];
int t[N];
signed main()
{
	fastio();
	int n,ans=0;
	cin>>n;
	for(int i=1;i<=n;++i)
		cin>>a[i];
	for(int i=1;i<=n;++i) t[i]=max(t[i-1],a[i]+1);
	for(int i=n-1;i>=1;--i)
		if(t[i+1]-t[i]>1)
			t[i]=t[i+1]-1;
    for(int i=1;i<=n;++i)
		ans+=t[i]-a[i]-1;
	cout<<ans<<endl;
    Please AC;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值