牛客多校第6场K-K-bag

题意

K-bag是一个正整数序列,由若干个 1 1 1~ k k k的排列排成,其连续子序列被称为部分K-bag。
给出一个序列和正整数 k k k,判断该序列是不是部分K-bag。
( n ≤ 5 e 5 , k ≤ 1 e 9 ) (n\leq5e5,k\leq1e9) (n5e5,k1e9)

题解

题目给的 k k k很大,所以在 k k k上做文章有点难。
考虑直接扫一遍,用 O ( n ) O(n) O(n)做法或 O ( n l o g n ) O(nlogn) O(nlogn)做法。
一开始若有数字大于 k k k直接输出。
设数组 f [ i ] f[i] f[i],记录序列 1 1 1~ i i i是否可以为一个部分K-bag。
为维护 f [ i ] f[i] f[i],我们需要定义一个 t o t tot tot,记录 ( i − k + 1 ) (i-k+1) (ik+1)~ i i i这一段上,一共有几种不同数字。
那么我们有需要一个哈希表来统计这一段上数字的出现数组,实现方式可以用 u n o r d e r e d _ m a p unordered\_map unordered_map(因为 m a p map map会超时)或离散化使数字均小于 5 e 5 5e5 5e5然后直接用数组哈希。
若序列用 a [ i ] a[i] a[i]表示,
那么就有 i f ( i > n & & ! − − h a s h [ a [ i − k ] )   t o t − − ; if(i>n\&\&!--hash[a[i-k])\ tot--; if(i>n&&!hash[a[ik]) tot; i f ( h a s h [ a [ i ] ] = = 0 )   t o t + + ; if(hash[a[i]]==0)\ tot++; if(hash[a[i]]==0) tot++;
i < k i<k i<k时, f [ i ] = t o t = = i ? 1 : 0 ; f[i]=tot==i?1:0; f[i]=tot==i?1:0;
i > = k i>=k i>=k时, f [ i ] = t o t = = k ? f [ i − k ] : 0 ; ( f [ 0 ] = 1 ) f[i]=tot==k?f[i-k]:0;(f[0]=1) f[i]=tot==k?f[ik]:0;(f[0]=1)
最后从后往前查找最后 k k k个数字,看最后这一段能否符合以及此处 f f f值是否为 1 1 1。找到一个符合条件的即为 Y E S YES YES,否则为 N O NO NO

#include<bits/stdc++.h>
int a[500010],f[500010],id[500010],tong[500010];
int main(){
    int T; scanf("%d",&T);
    while(T--){
        memset(tong,0,sizeof(tong)); memset(f,0,sizeof(f)); f[0]=1;
        int n,k,tag=0,tot=0,ans=0; scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",a+i),tag=a[i]>k?1:0,id[i]=a[i];
        std::sort(id+1,id+n+1);
        int len=std::unique(id+1,id+n+1)-id-1;
        for(int i=1;i<=n;i++) a[i]=std::lower_bound(id+1,id+len+1,a[i])-id;
        if(tag) {printf("NO\n");continue;}
        for(int i=1;i<=n;i++){
            if(i>k) if(!--tong[a[i-k]]) tot--;
            if(!tong[a[i]]) tot++;
            tong[a[i]]++;
            if(i>=k&&tot==k) f[i]=f[i-k];
            if(i<k&&tot==i) f[i]=1;
        }
        tot=0; memset(tong,0,sizeof(tong));
        for(int i=n;i>=std::max(n-k,0);i--){
            if(f[i]&&tot==n-i) {ans=1;break;}
            if(!tong[a[i]]) tot++;
            tong[a[i]]++;
        }
        if(ans) printf("YES\n"); else printf("NO\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值