Codeforces Round #825 (Div. 2)-C1. Good Subarrays (Easy Version)

题意:给定含有n个整数的数组a,找出所有满足这个条件的区间个数:[l,l+1,l+2……r],使得对于第i个位置上的元素,bi>=i(本文后面我们叫这样的区间为V)
假设有一个这样的数组:

样例一:
1, 2, 3, 4……
我们令c[i]为前i个数含有的V区间个数,那么对应的
c[1]=1
c[2]=c[1]+2=3
c[3]=c[2]+3=6
c[4]=c[3]+4=10

样例二:
1,2,1,4……
我们令c[i]为前i个数含有的V区间个数,那么对应的
c[1]=1
c[2]=c[1]+2=3
c[3]=c[2]+1=4
c[4]=c[3]+2=6
注意这里为什么不一样

先分析样例一:
对于a[4]=4,包含4的区间一共有4个
4,
3,4
2,3,4
1,2,3,4
不包括a[4]的有6个(这个6是根据a[1]~a[3]得到的)
那么c[4]=c[3]+4=10就是这样得到的

再分析样例二:
对于a[4]=4,包含4的区间一共有2个
4
1,4
不包括a[4]的有4个(这个6是根据a[1]~a[3]得到的)
那么c[4]=c[3]+2=6就是这样得到的

所以问题简化为,对于第i个数a[i],我们只需要求c[i-1]+包含a[i]的区间个数,包含a[i]的区间必须以a[i]为结尾

在两个样例中,在4往前走的时候,如果为3,那么还可以继续往前走;但是如果为1,就不能往前走了,因为题目中要求的第i个位置是的元素必须大于等于i,如果此时为1,那么它只能位于一个区间的第一个位置。所以第一个样例可以一直走到最前面(走了3步),含有4个满足条件的区间;第二个样例只能往前走1步,含有2两个满足条件的区间
每往前走一步,那么包含a[i]的区间就加一

所以可以得到c[i]=c[i-1]+min(id[i], a[i], d[i-1]+1)
第二个加式表示在前i个数里,包含a[i]的区间个数,记为d[i]
min(自身下标,自身的值,包含a[i-1]的V区间个数+1)

1、我们需要考虑不能一直往前,也就是小于等于它的下标
2、需要小于等于它自身的值
3、包含a[i-1]的V区间个数,加上它自己形成的一个V区间,也即d[i-1]+1
为了避免超时,我们可以把d[i]记录下来,当到i+1的时候,直接使用就行

#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<x<<" ";
#define Pu puts("");
#define sf(x) scanf("%d",&x);
typedef long long ll;
const int N=2e5+10,mod=100003;
const int inf=0x3f3f3f3f;
int a[N];
ll c[N];
int d[N];
int n,m;
int main(){
    int T;cin>>T;
    while(T--){
        cin>>n;
        for(int i=1;i<=n;i++){
            sf(a[i])
        }
        c[1]=1;
        d[1]=1;
        for(int i=2;i<=n;i++){
            d[i]=min(i,min(a[i],d[i-1]+1));
            c[i]=d[i]+c[i-1];
        }
        printf("%lld\n",c[n]);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值