首先把trie的广义后缀自动机建出来,那么任选起点在trie上走就是在SAM 的起点开始走。在SAM上求出sg函数,先手必胜当且仅当两个自动机上的节点的sg函数值不同。对第一个SAM的每个节点求出它在第二个SAM上对应的合法的路径条数【注意是路径条数,不是节点个数】,然后按照求字典序k小的方法dfs就可以了。
注意几个细节:
1.后继状态总数会爆long long,但是显然总数只需要存到
k
<script type="math/tex" id="MathJax-Element-21">k</script>。
2.一个点可能有好几条字母相同的出边,也就是其实给的不是trie。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=500010;
int trans[maxn][26],fail[maxn],val[maxn],sg[maxn],trie[maxn][26],rt[2],
que[maxn],id[maxn],cnt[maxn],ord[2][maxn],vis[30],corr[maxn],
n[2],t1[2],tot;
LL size[maxn],sum[maxn],num[maxn][30],k;
int add(int x,int u,int fl)
{
int nu,v,nv;
val[nu=++tot]=val[u]+1;
while (u&&!trans[u][x])
{
trans[u][x]=nu;
u=fail[u];
}
if (!u) fail[nu]=rt[fl];
else
{
v=trans[u][x];
if (val[v]==val[u]+1) fail[nu]=v;
else
{
val[nv=++tot]=val[u]+1;
fail[nv]=fail[v];
fail[nu]=fail[v]=nv;
for (int i=1;i<=26;i++) trans[nv][i]=trans[v][i];
while (u&&trans[u][x]==v)
{
trans[u][x]=nv;
u=fail[u];
}
}
}
return nu;
}
void build(int fl)
{
int x,hd,tl,u;
char c[3];
scanf("%d",&n[fl]);
for (int i=0;i<=n[fl];i++)
for (int j=1;j<=26;j++)
trie[i][j]=0;
for (int i=1;i<=n[fl];i++)
{
scanf("%d%s",&x,c);
if (!trie[corr[x]][c[0]-'a'+1]) trie[corr[x]][c[0]-'a'+1]=i;
corr[i]=trie[corr[x]][c[0]-'a'+1];
}
id[0]=rt[fl]=++tot;
que[hd=tl=1]=0;
while (hd<=tl)
{
u=que[hd++];
for (int i=1;i<=26;i++)
if (trie[u][i])
{
id[trie[u][i]]=add(i,id[u],fl);
que[++tl]=trie[u][i];
}
}
for (int i=0;i<=n[fl];i++) cnt[i]=0;
for (int i=rt[fl];i<=tot;i++) cnt[val[i]]++;
for (int i=1;i<=n[fl];i++) cnt[i]+=cnt[i-1];
for (int i=rt[fl];i<=tot;i++) ord[fl][cnt[val[i]]--]=i;
t1[fl]=tot-rt[fl]+1;
for (int i=t1[fl];i>=1;i--)
{
u=ord[fl][i];
memset(vis,0,sizeof(vis));
for (int j=1;j<=26;j++)
if (trans[ord[fl][i]][j])
vis[sg[trans[u][j]]]=1;
for (int j=0;;j++)
if (!vis[j])
{
sg[u]=j;
break;
}
}
}
void dfs(int fl,int u,LL k)
{
int x;
if (size[u]>=k)
{
putchar('\n');
if (fl) return;
for (int i=t1[1];i>=1;i--)
{
x=ord[1][i];
size[x]=sum[x]=(sg[x]!=sg[u]);
for (int j=1;j<=26;j++)
sum[x]+=sum[trans[x][j]];
}
dfs(1,rt[1],k);
return;
}
k-=size[u];
for (int j=1;j<=26;j++)
if (sum[trans[u][j]]>=k)
{
putchar('a'+j-1);
dfs(fl,trans[u][j],k);
return;
}
else k-=sum[trans[u][j]];
}
int main()
{
//freopen("c.in","r",stdin);
//freopen("c.out","w",stdout);
int u;
scanf("%lld",&k);
build(0);
build(1);
for (int i=t1[1];i>=1;i--)
{
u=ord[1][i];
num[u][sg[u]]=num[u][27]=1;
for (int j=1;j<=26;j++)
for (int k=0;k<=27;k++)
num[u][k]+=num[trans[u][j]][k];
}
for (int i=t1[0];i>=1;i--)
{
u=ord[0][i];
sum[u]=size[u]=num[rt[1]][27]-num[rt[1]][sg[u]];
for (int j=1;j<=26;j++)
{
sum[u]+=sum[trans[u][j]];
if (sum[u]>k+10) sum[u]=k+10;
}
}
if (k>sum[1])
{
printf("K is too large!\n");
return 0;
}
dfs(0,1,k);
}