2020牛客多校第六场K题K-Bag(离散化)

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

题意:定义一个概念kbag:1-k的排列。3bag表示为{1,2,3,2,1,3,3,2,1}长度不限,输入n,k,n长的序列,判断是不是part-kbag。 

题解:

ai<1ai>k,不为partKbag

由于可能有k>n,故此时需要离散化或者用map存,都是O(nlogn)

一个part-kbag的组成:一个或零个不完整的k排列+Kbag+一个或零个不完整的k排列。

考虑枚举起点,最多k个起点。首先找到每个元素可以到达的往后的最远位置,用len[i]表示位置在i的元素可到达的最远位置,如果为k则说明可以组成一个完整的k排列,

否则就判断是否有i+len[i]>=n+1,如果有则说明该起点得到了一个合法的partKbag,否则该起点得不到。

那么就可以枚举最多k个起点,说明从i到n可以组成一个不完整的k排列。

该种枚举方法考虑的是从Kbag+一个或零个不完整的k排列,开头的不完整的k排列自动判断正确。

 

 

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+7;
int a[maxn],b[maxn],pre[maxn],len[maxn];

int main(){
    int t,n,k;
    scanf("%d",&t);
    while(t--){
        memset(pre,0,sizeof(pre));
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+n+1);
        int cnt=unique(b+1,b+n+1)-(b+1);
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
        }
        int p=1,ans=0;
        for(int i=1;i<=n;i++){
            while( !pre[ a[p]] && p<=n) {
                pre[a[p]]++;
                p++;
            }
            pre[a[i]]--;
            len[i]=p-i;
        }
        for(int s=1;s<=min(k,len[1]+1);s++){
            int f=1;
            for(int i=s;i<=n;i+=k){
                if( i+len[i] >=n+1) continue;
                else if( len[i]^k){
                    f=0;break;
                }
            }
            if(f) {
                ans=1;break;
            }
        }
        if(ans) puts("YES");
        else puts("NO");
    }
    return 0;
} 

 

posted @ 2020-08-02 16:14  杰瑞与汤姆  阅读(196)  评论(0编辑  收藏  举报