题意:
给定一个序列a,每次走都会从i跳到i+a[i],并且可以把路径上的数都减去1,和1取max,问最小走多少趟把整个序列变为1。
思路:
由于可以都从1开始遍历,从前往后遍历,考虑第i个数被遍历的时候前面的数对ta造成的影响,由于每个数都要从a[i]降到2,是一段区间,显然可以差分维护,所以假设前面的贡献我们已经更新,我们计算可以少走多少趟,那还有个问题,如果前面的数对他造成的影响溢出了会怎么样呢?那么也就是说a[i]变成1以后又要多走溢出次的累计到后面的差分里去。那么这题就做完了。
// Problem: lzh的蹦床
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/20278/A
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int N = 5200;
const int mod=998244353;
inline int read()
{
int res=0;
int f=1;
char c=getchar();
while(c>'9' ||c<'0')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
res=(res<<3)+(res<<1)+c-'0';
c=getchar();
}
return res;
}
#define int long long
int n;
int T;
int d[N];
int a[N];
int b[N];
signed main()
{
cin>>T;
while(T--)
{
cin>>n;
ll res=0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++){
d[i]+=d[i-1];
res+=max(0ll,a[i]-d[i]-1);
d[i+2]++;
d[min(n+1,i+1+a[i])]--;
if(a[i]-d[i]>=1){
}
else if(a[i]-d[i]<1)
{
int k=1-(a[i]-d[i]);
d[i+1]+=k;
d[i+2]-=k;
}
}
cout<<res<<endl;
for(int i=1;i<=n+10;i++)
d[i]=0;
}
return 0;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/