51nod 1464 半回文 题解

题意简述

一个字符串S,长度5000(时间空间都够平方做),只有’a’和’b’两个字符组成。一个字符串A是“半回文”的,当且仅当,对于所有的奇数$i<=(|A|+1)/2$,满足A的正数第$i$个和$A$的倒数第$i$个相等。

请你求出,$S$的所有半回文的子串中,字典序排序第$k$位的是哪个。

思路框架

$dp$求出哪些子串是半回文的,加入到TRIE树中,用类似二叉查找树的方法找到第$k$个即珂。

具体思路

$dp[l][r]$表示$[l,r]$这一段子串是否是“半回文”的。如果$s[l]==s[r]$,才有珂能半回文,否则直接设为$0$。

如果l+2>=r-2,那么只需要满足$s[l]==s[r]$,就是半回文了。
否则,还需要使$dp[l+2][r-2]$为真,$dp[l][r]$才为真。

然后TRIE树上记录一个子树和。设指向字符’a’的是左儿子,’b’是右儿子。由于’a’的字典序小于’b’,所以,如果左儿子的size<=k,那么第$k-num[leftson]$个就在左子树里面。否则,就在右子树里面找第$k-num[rightson]$即珂。其中$num[u]$表示节点$u$是否表示一个半回文串。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 5333
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)

char s[N];
int k;int n;
void Input()
{
scanf("%s%d",s+1,&k); n=strlen(s+1);
}

class Trie //TRIE
{
public:
int num[N*1000];int T[N*1000][2];int cnt; //开个N*1000就够了
bitset<N> dp[N];int Max[N]; //bitset节省空间,大约是除以一个32的常数,因为其利用率高
void Init()
{
cnt=0;
D(i,n,1)
{
dp[i][i]=1;Max[i]=i;
F(j,i+1,n)
{
if (s[i]==s[j])
{
if (i+2>=j-2) dp[i][j]=1;
else dp[i][j]=dp[i+2][j-2];
}
if (dp[i][j]) Max[i]=max(Max[i],j); //Max[i]: 最远的j满足dp[i][j]=1
}
}
}
void Insert(int l,int r)
{
int pos=0;
F(i,l,r)
{
int id=s[i]-'a';
if (T[pos][id]==0) T[pos][id]=++cnt;
if (dp[l][i]) num[T[pos][id]]++; //暴力插入,反正平方能做

pos=T[pos][id];
}
}
string ans;
void DFS(int u)
{
string tmp=ans;
if (k>0 and T[u][0])
{
k-=num[T[u][0]];
ans+='a';
DFS(T[u][0]);
}
if (k>0 and T[u][1])
{
ans=tmp;
k-=num[T[u][1]];
ans+='b';
DFS(T[u][1]);
}
}
}T;
void Soviet()
{
T.Init();
F(i,1,n) T.Insert(i,T.Max[i]);
T.DFS(0);
printf("%s\n",T.ans.c_str());
}

#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}
w