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<1或ai>k,不为partK−bag
由于可能有k>n,故此时需要离散化或者用map存,都是O(nlogn)
一个part-k−bag的组成:一个或零个不完整的k排列+K−bag+一个或零个不完整的k排列。
考虑枚举起点,最多k个起点。首先找到每个元素可以到达的往后的最远位置,用len[i]表示位置在i的元素可到达的最远位置,如果为k则说明可以组成一个完整的k排列,
否则就判断是否有i+len[i]>=n+1,如果有则说明该起点得到了一个合法的partK−bag,否则该起点得不到。
那么就可以枚举最多k个起点,说明从i到n可以组成一个不完整的k排列。
该种枚举方法考虑的是从K−bag+一个或零个不完整的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; }