2020牛客暑期多校训练营第六场K-Bag

K-Bag

原题请看这里

题目描述

当一个数列可以表示为若干个 1 1 k k 的排列依次组成时,这个数列被称为 k b a g k-bag 。例如 1 , 2 , 3 , 2 , 1 , 3 , 3 , 2 , 1 1,2,3,2,1,3,3,2,1 是一个 3 b a g 3-bag
如果一个序列是一个 k b a g k-bag 的连续子串,则其称为 p a r t k b a g part-k-bag
求一个长度为 n n 的序列是否是一个 p a r t k b a g part-k-bag

输入描述:

第一行包含一个整数 T ( 1 T 20 ) T(1≤T≤20) ,表示测试用例的数量。
然后是 T T 个样例。每个测试案例的第一行包含两个整数 n , k 1 n 5 1 0 5 , 1 k 1 0 9 n,k(1≤n≤5⋅10^5,1≤k≤10^9)
每个测试案例的第二行包含n个整数表示序列。保证 n 2 1 0 6 ∑n≤2⋅10^6 ,序列的值在 1 1 1 0 9 10 ^ 9 之间。

输出描述:

如果一个序列是部分 k b a g k-bag 序列,则打印 Y E S “YES” ,否则打印 N O “NO”

样例输入:

1
8 3
2 3 2 1 3 3 2 1

样例输出:

YES

思路:

这题我调了8个小时!没错,你没听错,就是8个!
刚开始,我一看到这道题目就大叫一声:这不是签到题嘛!然后就兴冲冲的 W A WA 了一发 . . . . . . ......
再一看,原来没有这么简单,又打了一会儿,又兴冲冲的 W A WA 了一发 . . . . . . ......
然后就 w h i l e ( t r u e ) while(true) p r i n t f ( " W A " ) ; printf("WA"); ( ( T T 都不给 T ) T)
咳咳,回归正题
我们首先可以想到的解法: f o r for 寻找分割点,然后判断分割点是否合法,但显然会超时
随后,我们可以想到:只要在每两个相同的数之间的区间内有分割点就可以了,由于分割点是每k个数一个,所以我们可以把所有的区间都向前移 a k a*k 位,如果都有交集,说明是合法的。
但很快就又 W A WA 了,为什么呢?
在这里插入图片描述
这就是反例。
我们就应该维护两端的区间而不是只考虑一端的区间,这就需要用到前缀和来解决。
将一个区间的左端点 + 1 +1 ,右端点 1 -1 ,再统计一下前缀和就可以发现:前缀和数组中的数就是当前位置覆盖的区间数,最后只要找有没有数值等于区间数就可以了
由于k的取值有 1 e 9 1e9 ,所以我们需要对输入的数组离散化在进行操作,具体步骤请看代码。

AC Code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e6+5;
int n,k,t,fl,lsh,lap[MAXN],qian[MAXN],cnt;
int a[MAXN],b[MAXN];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        fl=1,cnt=0;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
            if(a[i]>k) fl=0;//如果输入的数大于k,那么就肯定不行
        }
        if(!fl)
        {
			puts("NO");
			continue;
		}
        sort(b+1,b+1+n);
        int QAQ=unique(b+1,b+1+n)-b-1;
       	for(int i=1;i<=n;i++)
       		a[i]=lower_bound(b+1,b+1+QAQ,a[i])-b;
       	//离散化
        memset(lap,0,sizeof(lap));
        memset(qian,0,sizeof(qian));//前缀和
        for(int i=1;i<=n;i++)
        {
            if(lap[a[i]]&&lap[a[i]]>i-k)//是否有相同的数出现
            {
                cnt++;//区间数
                qian[lap[a[i]]%k]++;
                qian[i%k]--;
                if(lap[a[i]]%k>=i%k)
                {
                    qian[0]++;
                    qian[min(k,n+1)]--;
                }
            }
            lap[a[i]]=i;
        }
        for(int i=0;i<=min(n,k-1);i++)
        {
            if(i) qian[i]+=qian[i-1];
            if(qian[i]==cnt)
            {
            	fl=0;
            	break;
            }//如果有符合的值就跳出
        }
        if(fl) puts("NO");
        else puts("YES");
    }
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107640121
今日推荐