牛客挑战赛39 密码系统 后缀数组

LINK:密码系统

容易发现一共有k种不同的划分 而每种划分中我们要求出字典序最大的那个然后和其他的比较求出字典序最小的。

先考虑如何求出最大的 容易发现这是字典序的问题 求出sa数组然后倒着扫描就行了 分段的话按i%k分即可。

求出最大的了之后考虑如何求出最小的 容易发现还是sa数组看一下他们之间的相对位置 靠前的必然字典序要优。

值得一提的是 后缀数组虽然难写 但是思想很好懂 按照思想来写不容易写错 而不是靠硬背。

//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define ldb long double
#define pb push_back
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define pii pair<int,int> 
#define mk make_pair
#define RE register
#define P 1000000007
#define S second
#define F first
#define mod 998244353
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define ull unsigned long long
#define ui unsigned
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=1000010<<1;
int n,m,k;
char a[MAXN];int vis[MAXN];
int c[MAXN],x[MAXN],y[MAXN],sa[MAXN],rk[MAXN],h[MAXN];
inline void SA()
{
	m=150;
	rep(1,n,i)++c[x[i]=a[i]];
	rep(1,m,i)c[i]+=c[i-1];
	rep(1,n,i)sa[c[x[i]]--]=i;
	for(int k=1;k<=n;k=k<<1)
	{
		int num=0;
		rep(n-k+1,n,i)y[++num]=i;
		rep(1,n,i)if(sa[i]>k)y[++num]=sa[i]-k;
		rep(1,m,i)c[i]=0;
		rep(1,n,i)++c[x[i]];
		rep(1,m,i)c[i]+=c[i-1];
		fep(n,1,i)sa[c[x[y[i]]]--]=y[i];
		rep(1,n,i)y[i]=x[i],x[i]=0;
		x[sa[1]]=num=1;
		rep(2,n,i)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?num:++num;
		if(num==n)break;
		m=num;
	}
	rep(1,n,i)rk[sa[i]]=i;
}
inline void get_H()
{
	int k=0;
	rep(1,n,i)
	{
		if(rk[i]==1)continue;
		if(k)--k;
		int j=sa[rk[i]-1];
		while(a[i+k]==a[j+k])++k;
		h[rk[i]]=k;
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	gt(n);gt(k);gc(a);
	rep(1,n,i)a[i+n]=a[i];
	n=n<<1;SA();get_H();
	//rep(1,n,i)put(rk[i]);
	int en=k+n/2-1,st;//有效部分.
	fep(n,1,i)
	{
		if(sa[i]>en)continue;
		int ww=sa[i]%k;
		if(vis[ww])continue;
		vis[ww]=1;st=i;
	}
	rep(sa[st],sa[st]+k-1,i)putchar(a[i]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/chdy/p/12745883.html