Codeforces1491——C.Pekora and Trampoline(差分思维+树状数组)

原题链接
There is a trampoline park with n trampolines in a line. The i-th of which has strength Si.

Pekora can jump on trampolines in multiple passes. She starts the pass by jumping on any trampoline of her choice.

If at the moment Pekora jumps on trampoline i, the trampoline will launch her to position i+Si, and Si will become equal to max(Si−1,1). In other words, Si will decrease by 1, except of the case Si=1, when Si will remain equal to 1.

If there is no trampoline in position i+Si, then this pass is over. Otherwise, Pekora will continue the pass by jumping from the trampoline at position i+Si by the same rule as above.

Pekora can’t stop jumping during the pass until she lands at the position larger than n (in which there is no trampoline). Poor Pekora!

Pekora is a naughty rabbit and wants to ruin the trampoline park by reducing all Si to 1. What is the minimum number of passes she needs to reduce all Si to 1?

Input
The first line contains a single integer t (1≤t≤500) — the number of test cases.

The first line of each test case contains a single integer n (1≤n≤5000) — the number of trampolines.

The second line of each test case contains n integers S1,S2,…,Sn (1≤Si≤109), where Si is the strength of the i-th trampoline.

It’s guaranteed that the sum of n over all test cases doesn’t exceed 5000.

Output
For each test case, output a single integer — the minimum number of passes Pekora needs to do to reduce all Si to 1.

Example
inputCopy
3
7
1 4 2 2 2 2 2
2
2 3
5
1 1 1 1 1
outputCopy
4
3
0
Note
For the first test case, here is an optimal series of passes Pekora can take. (The bolded numbers are the positions that Pekora jumps into during these passes.)

[1,4,2,2,2,2,2]
[1,4,1,2,1,2,1]
[1,3,1,2,1,1,1]
[1,2,1,2,1,1,1]
For the second test case, the optimal series of passes is show below.

[2,3]
[1,3]
[1,2]
For the third test case, all Si are already equal to 1.

题意:
在这里插入图片描述

思路:
首先,贪心的考虑,从 a i > 1 a_{i}>1 ai>1的点起跳是最优的。
然后,考虑每个点的贡献。假设当前高度为 a i a_{i} ai,那么从i点能够跳到后面的 [ i + 1 , i + s i ] [i+1,i+s_{i}] [i+1,i+si]
我们可以确定的是,对 [ i + 2 , i + s i ] [i+2,i+s_{i}] [i+2,i+si]的贡献都为1,涉及到区间修改,最容易想到的就是差分。这样就可以计算出i点对该段区间的贡献了。关于对i+1的贡献,该部分为0,因为当i==1时,不会选择该点为起点 (从前面跳到i点再继续往后跳的情况在下文)
假设 t i t_{i} ti表示i点被前面的点经过多少次,分下面几种情况考虑:
1.如果 t i − s i > 1 t_{i}-s_{i}>1 tisi>1的话,因为当高度为1时就不会减少了,所以对i点不会产生贡献,从高度为1的i点会跳到i+1点,剩下的就是对i+1的贡献。
2.如果 t i − s i < 1 t_{i}-s_{i}<1 tisi<1,说明前面的点不能使得该点变为高度为1,要再从这个点起跳。
维护的操作用的树状数组,复杂度nlogn。

代码:

///#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b, ll p)
{
    ll res = 1;
    while(b)
    {
        if(b & 1)res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
const int inf = 0x3f3f3f3f;
#define PI acos(-1)
const double eps = 1e-8;
const int maxn = 2e5 + 7;
int n,a[maxn];
ll tr[maxn];
ll lowbit(ll x){
    return x&(-x);
}
void update(ll pos,ll val){
	while(pos<=n){
		tr[pos]+=val;
		pos+=lowbit(pos);
	}
}
ll qask(ll pos){
	ll res=0;
	while(pos){
		res+=tr[pos];
		pos-=lowbit(pos);
	}
	return res;
}
void solve(){
	n=read;
	memset(tr,0,sizeof tr);
	rep(i,1,n) a[i]=read;
	ll res=0;
	for(int i=1;i<=n;i++){
		int tmp=a[i]-qask(i);
		if(tmp>1) res+=tmp-1;///还要从这个点起跳使这个点变为1
		if(a[i]>1) update(i+2,1),update(i+a[i]+1,-1);///计算对后面点的贡献
		if(tmp<1){
			///该点正好可以为1,考虑对i+1的影响
			update(i+1,1-tmp);update(i+2,tmp-1);
		}
	}
	printf("%lld\n",res);
}

int main()
{
	int T=read;
	while(T--) solve();
    return 0;
}
posted @ 2021-03-16 15:38  OvO1  阅读(55)  评论(0编辑  收藏  举报