Problem
给出一个字符串,求这个串中本质不同的回文子串个数以及这些本质不同的回文子串中第K小的串。
Input
Output
Hint
Solution
首先,我们发现它要求本质不同的回文子串个数,于是马上联想到回文自动机。看看数据,
105
10
5
,非常稳。于是第一问就用回文自动机解掉。不知道回文自动机的戳这里→这里写链接内容
那么只剩下第二问了。很容易想到快排,然后直接输出第K小。但是理论上最坏复杂度为
O(n2log2)
O
(
n
2
l
o
g
2
)
(快排复杂度×(字符串大小比较+交换字符串))。我们发现交换字符串一定会耗费大量时间,于是可以直接把字符串的编号丢进一个数组里,然后比较时就比较它们对应的字符串,交换则交换编号。
那么时间复杂度就变为:快排复杂度×字符串大小比较。
上式看似很大,但是实际上我们在比较字符串大小时,基本上是
O(1)
O
(
1
)
的——因为随机数据下,两个字符串的长度一般都不相等。而且即使相等,它基本上也会在比较完前面少数字符后就知道了谁大谁小。于是此法就能优美地通过。
时间复杂度:
O(能过)
O
(
能
过
)
。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
const int MAXN = 100005 ;
const int N = 26 ;
char s[MAXN];
int i,x,n,d[MAXN],head,tail,a[MAXN];
ll P,ans,K;
struct Palindromic_Tree
{
int next[MAXN][N],fail[MAXN],num[MAXN],len[MAXN],S[MAXN],last,n,p,cur,now,fat[MAXN];
ll cnt[MAXN];
char ch[MAXN];
int newnode(int l) //新建节点
{
int i;
fo(i,0,N-1)next[p][i] = 0 ;
cnt[p] = 0 ;
num[p] = 0 ;
len[p] = l ;
if(p>1)a[p-1]=p;
return p ++ ;
}
inline void init() //初始化
{
p = 0 ;
newnode(0) ;
newnode(-1) ;
last = 0 ;
n = 0 ;
S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
fail[0] = 1 ;
}
int get_fail(int x) //和KMP一样,失配后找一个尽量最长的
{
while(S[n - len[x] - 1] != S[n]) x = fail[x] ;
return x ;
}
void add(int c,int pos)
{
c -= 'a';
S[++ n] = c ;
cur = get_fail(last); //通过上一个回文串找这个回文串的匹配位置
if(!next[cur][c]) //如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
{
now = newnode(len[cur] + 2),i; //新建节点
fail[now] = next[get_fail(fail[cur])][c] ; //和AC自动机一样建立fail指针,以便失配后跳转
next[cur][c] = now ;
fat[now]=cur;
ch[now]=c+'a';
num[now] = num[fail[now]] + 1 ;
}
last = next[cur][c] ;
cnt[last]++;
}
void count()
{
int i;
fd(i,p-1,2)cnt[fail[i]]+=cnt[i] ;
}
}run;
inline bool compare(int x,int y)
{
if(run.len[x]!=run.len[y])return run.len[x]<run.len[y];
while(x>1)
{
if(run.ch[x]!=run.ch[y])return run.ch[x]<run.ch[y];
x=run.fat[x];
y=run.fat[y];
}
}
int main()
{
scanf("%d%lld",&n,&P);
scanf("%s",&s);
run.init();
fo(i,0,n-1)run.add(s[i],i);
run.count();
ans=run.p-2;
printf("%lld\n",ans);
K=P%ans+1;
sort(a+1,a+run.p-1,compare);
x=a[K];
n=run.len[x];
i=0;
while(x>1)
{
s[i]=s[n-i-1]=run.ch[x];
x=run.fat[x];
i++;
}
fo(i,0,n-1)putchar(s[i]);
}