2020牛客多校第六场K题题解

K-Bag

https://ac.nowcoder.com/acm/contest/5671/K

比赛的时候是队友写的,用ST表实现了一下。
首先想到,枚举所有可能的区间划分方法,只要存在一种划分使得每个区间里的数字恰好出现一次即可,因为区间里1~k都要出现,也就相当于求是否存在一个出现了两次及以上的数字。
用一个数组记录每个数字和左边最近的与它相同的数字的下标。每次查询区间的最大值,如果最大值大于等于区间的左端点,说明存在一个数,在这个区间里出现了至少两次。此时的划分方法就是不合法的。

#include<bits/stdc++.h>
using namespace std;
const int N=2000007;
int t,n,k,a[N],st[N][20],f[N],lg[N];
void init_st(){
    for(int i=1;i<=n;++i)st[i][0]=i;
    for(int j=1;j<20;++j)for(int i=1;i<=n;++i){
        if(f[st[i][j-1]]>f[st[i+(1<<(j-1))][j-1]])st[i][j]=st[i][j-1];
        else st[i][j]=st[i+(1<<(j-1))][j-1];
    }
}
int rmq(int l,int r){
    return max(f[st[l][lg[r-l+1]]],f[st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]]);
}
bool check(){
    for(int i=1;i<=min(n,k);++i){
        bool flag=1;
        if(rmq(1,i))continue;
        for(int j=i+1;j<=n;j+=k)if(rmq(j,min(n,j+k-1))>=j)flag=0;
        if(flag)return 1;
    }
    return 0;
}
int main(){
    ios::sync_with_stdio(false);
    for(int i=2;i<N;++i)lg[i]=lg[i/2]+1;
    cin>>t;
    while(t--){
        cin>>n>>k;
        for(int i=1;i<=n;++i)cin>>a[i];
        map<int,int> M;
        for(int i=1;i<=n;++i){
            f[i]=M[a[i]];
            M[a[i]]=i;
        }
        init_st();
        if(check())cout<<"YES"<<endl;else cout<<"NO"<<endl;
    }
    return 0;
}
全部评论

相关推荐

Java面试先知:我也是和你一样的情况,hr 说等开奖就行了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务