您的位置:首页 > 其它

[广义后缀自动机 SG值] 51Nod 1869 那些年,我们一起讲的故事

2017-06-13 21:58 387 查看
简直 在众人的帮助下理解了一个假题意 看完题解知道真题意

大概是每次加一个字符 这个串仍然要是Trie树的子串

直接建SAM 然后求SG值 不超过度数+1 也就是27

然后先手必胜 两边SG不同 那么按字典序数一数就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cassert>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void read(ll &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void read(char &x){
for (x=nc();!(x>='a' && x<='z');x=nc());
}

const int N=400005;

struct SAM{
struct state{
int link,len,next[26];
}st
;
int last,ncnt;
void Extend(int c){
if (st[last].next[c]){
int q=st[last].next[c];
if (st[q].len==st[last].len+1)
last=q;
else{
int nq=++ncnt;
st[nq].link=st[q].link; st[q].link=nq;
st[nq].len=st[last].len+1;
for (int i=0;i<26;i++) st[nq].next[i]=st[q].next[i];
for (int p=last;p && st[p].next[c]==q;p=st[p].link)
st[p].next[c]=nq;
last=nq;
}
}else{
int cur=++ncnt,p;
st[cur].len=st[last].len+1;
for (p=last;p && !st[p].next[c];p=st[p].link)
st[p].next[c]=cur;
if (!p)
st[cur].link=1;
else{
int q=st[p].next[c];
if (st[q].len==st[p].len+1)
st[cur].link=q;
else{
int nq=++ncnt;
st[nq].link=st[q].link;
st[nq].len=st[p].len+1;
for (int i=0;i<26;i++) st[nq].next[i]=st[q].next[i];
for (;p && st[p].next[c]==q;p=st[p].link)
st[p].next[c]=nq;
st[cur].link=nq; st[q].link=nq;
}
}
last=cur;
}
}
int tmp
,sum
,c
;
inline void Sort(){
for (int i=1;i<=ncnt;i++) c[st[i].len]++;
for (int i=1;i<=100000;i++) c[i]+=c[i-1];
for (int i=1;i<=ncnt;i++) tmp[c[st[i].len]--]=i;
}
ll cnt
[27],tot
; int sg
;
int clk,vst[27];
void Pre(){
for (int i=ncnt;i;i--){
int x=tmp[i]; ++clk;
for (int j=0;j<26;j++){
if (!st[x].next[j]) continue;
vst[sg[st[x].next[j]]]=clk;
tot[x]+=tot[st[x].next[j]];
for (int k=0;k<=26;k++)
cnt[x][k]+=cnt[st[x].next[j]][k];
}
sg[x]=-1;
for (int j=0;j<=26;j++) if (vst[j]!=clk) { sg[x]=j; break; }
assert(sg[x]!=-1);
cnt[x][sg[x]]++; tot[x]++;
}
}
ll Tot(int x,int c){
return tot[x]-cnt[x][c];
}
}A,B;

char sa
,sb
;
int na,nb;

inline void solve(ll K,int c){
int x=1;
while (1){
if (K==1 && B.sg[x]!=c)
return;
K-=B.sg[x]!=c;
for (int j=0;j<26;j++){
if (!B.st[x].next[j]) continue;
if (K<=B.Tot(B.st[x].next[j],c)){
x=B.st[x].next[j]; sb[++nb]='a'+j; break;
}else{
K-=B.Tot(B.st[x].next[j],c);
}
}
}
}

ll Sum
,Val
;

inline void Solve(ll K){
for (int i=A.ncnt;i;i--){
int x=A.tmp[i];
Sum[x]=Val[x]=B.Tot(1,A.sg[x]);
for (int j=0;j<26;j++){
if (!A.st[x].next[j]) continue;
Sum[x]+=Sum[A.st[x].next[j]];
if (Sum[x]>1e18) Sum[x]=1e18;
}
}
if (K>Sum[1]){
printf("K is too large!\n"); exit(0);
}
int x=1;
while (1){
if (K<=Val[x]){
solve(K,A.sg[x]); return;
}else{
K-=Val[x];
for (int j=0;j<26;j++){
if (!A.st[x].next[j]) continue;
if (K<=Sum[A.st[x].next[j]]){
sa[++na]='a'+j; x=A.st[x].next[j]; break;
}else{
K-=Sum[A.st[x].next[j]];
}
}
}
}
}

struct edge{
int u,v,next;
}G[N<<1];
int head
,inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int val
;
#define V G[p].v

inline void dfs(int u,SAM &A){
int tmp=A.last; if (u) A.Extend(val[u]);
for (int p=head[u];p;p=G[p].next)
dfs(V,A);
A.last=tmp;
}

int main(){
ll K; int n,p; char c;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(K);
read(n);
for (int i=1;i<=n;i++)
read(p),read(c),add(p,i,++inum),val[i]=c-'a';
A.last=A.ncnt=1; dfs(0,A);
A.Sort(); A.Pre();
cl(head); inum=0;
read(n);
for (int i=1;i<=n;i++)
read(p),read(c),add(p,i,++inum),val[i]=c-'a';
B.last=B.ncnt=1; dfs(0,B);
B.Sort(); B.Pre();
Solve(K);
printf("%s\n%s\n",sa+1,sb+1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: