题目链接
https://codeforces.com/contest/1736/problem/C1
题意简述
对于一个有
m
m
m 个元素的数组
b
b
b ,如果满足
∀
i
∈
[
1
,
m
]
,
b
i
≥
i
\forall i \in [1,m],b_i\geq i
∀i∈[1,m],bi≥i,就称数组
b
b
b 是
g
o
o
d
good
good .
现在给你一个数组,请你找出这个数组最多有多少个连续子序列构成的数组是
g
o
o
d
good
good
样例
点击查看样例分析
蒟蒻居然自己做出来了…
不难发现,结论
①
:
①:
①:如果
a
i
=
x
a_i=x
ai=x ,那么
a
i
a_i
ai在一个新数组的下标最多是
x
x
x.
并且我们发现,结论
②
:
②:
②:对于一个
g
o
o
d
good
good 的数组
b
b
b ,把他前面任意连续个元素去掉,剩下的元素组成的数组仍然是
g
o
o
d
good
good 的.
如果以第
i
−
1
i-1
i−1个元素结尾的长度是
y
y
y ,那么如果
a
i
>
y
a_i>y
ai>y,那么以
a
i
a_i
ai结尾的最长数组长度就是
y
+
1
y+1
y+1, 如果
a
i
≤
y
a_i\leq y
ai≤y ,那么由结论②,不妨就取后
y
−
1
y-1
y−1 个元素与
a
i
a_i
ai 组成新数组.此时以
a
i
a_i
ai 结尾的最长数组长度就是
a
i
a_i
ai 的值.
设
d
p
[
i
]
dp[i]
dp[i] 是以第
i
i
i 个元素结尾的最长的
g
o
o
d
good
good 数组的长度
if(a[i]>=dp[i-1]+1) dp[i]=dp[i-1]+1
if(a[i]<dp[i-1]+1) dp[i]=a[i]
那么状态转移方程 d p [ i ] = m i n ( a i , d p [ i − 1 ] + 1 ) dp[i]=min(a_i,dp[i-1]+1) dp[i]=min(ai,dp[i−1]+1)
最后所有可能的分类的方法数是以 i i i 结尾的数组长度之和.
代码
点击查看代码#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<string.h>
#include<algorithm>
#define int long long
using namespace std;
typedef long long LL;
const int N=2e5+10;
int a[N];
int dp[N];
int n;
signed main()
{
//freopen("uva.txt","r",stdin);
int T;
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
dp[1]=1;
int res=1;
for(int i=2;i<=n;i++)
{
dp[i]=min(dp[i-1]+1,a[i]);
res+=dp[i];
}
printf("%lld\n",res);
}
return 0;
}