D. Speedbreaker

Posted on 2024-10-30 21:28  Capterlliar  阅读(3)  评论(0编辑  收藏  举报

题意:给定长为n的数组a,a[i]属于[1, n]。开始时时刻为1,可以选定其中一个数,接下来每个时刻选定与已选定的数相邻的其他数,要求每个数被选定的时刻小于等于它的值。求满足这一条件的起点的数目。

解:对于每个a[i],其要求起点的范围为[i-a[i]+1, i+a[i]-1],将n个区间取交集,即为可能的答案区间。接下来考虑什么情况会没有解。举一个栗子:

5 6 4 1 4 5

左右两边都要求在时刻5及其之前被选定,但两者相距6个数,显然不可能满足条件。于是简单的得出一个结论:令numl[i]和numr[i]为数字i在a中最左边和最右边的位置,如果包括左右两点其距离大于i,那么无解。

(然后WA了)

事情并没有这么简单,再看一个栗子:

3 4 4 5 4

这种情况同样无解,虽然左边的4和右边的4之间刚好是4个数,但左边还有一个3,3肯定要在4之前被选定,于是就来不及选另一个4了。于是扩展结论:令numl[i]和numr[i]为数字i及小于i的数在a中最左边和最右边的位置,如果包括左右两点其距离大于i,那么无解。

在之前的基础上加一个类似前缀和的运算即可。

(有点丑陋的)代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define inf 0x3f3f3f3f

int n;
int a[maxx]={0};
int l[maxx]={0},r[maxx]={0};
int numl[maxx]={0},numr[maxx]={0};

signed main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int s=1,e=n;
        for(int i=0;i<=n+1;i++){
            numl[i]=n+1;
            numr[i]=0;
            l[i]=r[i]=0;
        }
        for(int i=1;i<=n;i++){
            numl[a[i]]=i;
            numr[a[i]]=i;
            l[i]=max(s,i-a[i]+1);
            r[i]=min(e,i+a[i]-1);
        }
        for(int i=1;i<=n;i++){
            numl[a[i]]=min(numl[a[i]],i);
            numr[a[i]]=max(numr[a[i]],i);
        }
        for(int i=1;i<=n;i++){
            numl[i]=min(numl[i],numl[i-1]);
        }
        for(int i=1;i<=n;i++){
            numr[i]=max(numr[i],numr[i-1]);
        }

        // printf("num i left pos:\n");
        // for(int i=1;i<=n;i++) printf("%d ",numl[i]);
        // printf("\nnum i right pos:\n");
        // for(int i=1;i<=n;i++) printf("%d ",numr[i]); printf("\n");
        // for(int i=1;i<=n;i++) printf("%d ",l[i]); printf("\n");
        // for(int i=1;i<=n;i++) printf("%d ",r[i]); printf("\n");

        for(int i=1;i<=n;i++){
            if(numr[i]-numl[i]+1>i){
                printf("0\n");
                goto nxt;
            }
        }
        for(int i=1;i<=n;i++){
            s=max(s,l[i]);
            e=min(e,r[i]);
        }
        printf("%d\n",max(0,e-s+1));
        nxt:;
    }
    return 0;
}
View Code