首页 > 其他分享 >D. Speedbreaker

D. Speedbreaker

时间:2024-10-30 21:20:19浏览次数:1  
标签:maxx 选定 numr int numl Speedbreaker define

题意:给定长为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

 

 

标签:maxx,选定,numr,int,numl,Speedbreaker,define
From: https://www.cnblogs.com/capterlliar/p/18516651

相关文章

  • B. Speedbreaker
    链接:https://codeforces.com/problemset/problem/2018/B题目:思路:刚开始的思路是对的,就是每个点确定范围求交集。然后还要判断一下会不会无解,比如[5,6,4,1,4,5],就是说∃t∈[1,n],st:a[x]<=n,a[y]<=n,max(x)-min(y)>=t时无解,因为两侧如果更大、更小就会冲突。代码:#include<ios......
  • CF2019D Speedbreaker
    题意Link一个数轴上有\(1,2,\dots,n\)共\(n\)个点。第\(1\)秒时,你将从其中一个点开始染色,称为初始点,之后第\(2,3,\dots,n\)秒,你每秒可以将一个被染色的点左边或右边的点染色。每个点有一个时间限制,必须要在\(a_i\)秒前(包含第\(a_i\)秒)被染色,问有多少个初始点可以将......
  • CF2019D. Speedbreaker 题解
    介绍一种另解,以下称“征服”为“拓展”。对于这些需要拓展,且拓展的时间有上界的题,我们通常都会有一个trick。那就是对于一个点\(x\),用它可以拓展到的点\(y\)的时间上界把\(x\)的时间上界继续缩小。用到这种trick的题有P9755[CSP-S2023]种树、[ABC304Ex]ConstrainedTop......