2021.7.18 义乌模拟赛 T2 子序列
这个东西的\(k\)很小,考虑爆搜。
首先我们对于每层爆搜我们要保证每次搜到的是最优的。
而且我们还要同种的一起处理。
我们考虑对每一层开一个vector,存的是当前搜到的可以作为一个end的位置可重集合。
然后每次扩展肯定是找到这一范围内最小的没被搜过的点进行。这个可以用主席树维护后缀k小值实现。
然后我们对于这些进行尺取,找到每个这种颜色的可以成为几个后缀,然后搜下去即可。
时间复杂度是\(O(klogn)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100000
#define M 50000
#define mod 1000000000
#define mod2 39989
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,k,seed,p,Maxn,A[N+5],cnt,root[N+5];vector<int> G[N+5],F[N+5];
struct kthTree{
int F[N+5<<5],ls[N+5<<5],rs[N+5<<5],cnt,i;
I void insert(int x,int &now,int l=1,int r=N){F[++cnt]=F[now]+1;ls[cnt]=ls[now];rs[cnt]=rs[now];now=cnt;if(l==r) return;int m=l+r>>1;x<=m?insert(x,ls[now],l,m):insert(x,rs[now],m+1,r);}
I int Query(int x,int now,int l=1,int r=N){int m;while(l^r) m=l+r>>1,F[ls[now]]<x?(x-=F[ls[now]],now=rs[now],l=m+1):(now=ls[now],r=m);return l;}
I void Make(int *B){for(i=n;i;i--)root[i]=root[i+1],insert(A[i],root[i]);}
}T;
I void dfs(int x,ll W){
int i,j,now=0,las,pus,tot,h,S=G[x][0],ks;W=W*seed%p;for(i=1;i<=n-S;i++){
now=T.Query(i,root[S+1]);if(i^1&&las==now) continue;las=now;G[x+1].clear();pus=upper_bound(F[now].begin(),F[now].end(),S)-F[now].begin();
for(h=tot=0,j=pus;j<F[now].size();j++) {
while(h<G[x].size()&&F[now][j]>G[x][h]) tot++,h++;if(k<=tot){while(k--)printf("%lld\n",(W+now)%p);exit(0);}
for(ks=1;ks<=tot;ks++) k--,printf("%lld\n",(W+now)%p),G[x+1].push_back(F[now][j]);
}dfs(x+1,(W+now)%p);
}
}
int main(){
// freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
re int i,j;scanf("%d%d%d%d",&n,&k,&seed,&p);for(i=1;i<=n;i++)scanf("%d",&A[i]),Maxn=max(Maxn,A[i]),F[A[i]].push_back(i);
T.Make(A);G[1].push_back(0);dfs(1,0);
}