1. 程式人生 > 實用技巧 >2020牛客多校第六場K題K-Bag(離散化)

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; }