【前言】
认真看完了
PAM
\text{PAM}
PAM的国集论文,学会了不基于势能分析的方式。
然而还是没有写过可持久化。
【题目】
CF245H Queries for Number of Palindromes
CF
给定一个长度为
n
n
n的字符串,
q
q
q组询问区间字符串有多少回文串。
n
≤
5
×
1
0
3
,
q
≤
1
0
6
n\leq 5\times 10^3,q\leq 10^6
n≤5×103,q≤106
裸题。
O
(
n
2
+
q
)
O(n^2+q)
O(n2+q)
事实上这是最后一道写的,不过这里用的是基于势能分析的写法,就放在了第一个。
#include<bits/stdc++.h>
using namespace std;
const int N=5005;
int Q,m,res,ans[N][N];
char s[N];
namespace IO
{
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void write(int x){if(x>9)write(x/10);putchar(x%10^48);}
void writeln(int x){write(x);putchar('\n');}
}
struct PAM
{
char a[N];
int n,las,sz,fa[N],len[N],dep[N],ch[N][26];
void init()
{
memset(a,'\0',sizeof(a));memset(fa,0,sizeof(fa));memset(len,0,sizeof(len));
memset(dep,0,sizeof(dep));memset(ch,0,sizeof(ch));
las=n=0;fa[0]=sz=1;len[1]=-1;
}
void extend(int x)
{
a[++n]=x^'a';int p=las,q,now;
while(a[n-len[p]-1]^a[n]) p=fa[p];
if(!ch[p][x])
{
q=++sz;len[q]=len[p]+2;now=fa[p];
while(a[n-len[now]-1]^a[n]) now=fa[now];
fa[q]=ch[now][x];dep[q]=dep[fa[q]]+1;ch[p][x]=q;
}
las=ch[p][x];res+=dep[las];
}
}S;
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF245H.in","r",stdin);
freopen("CF245H.out","w",stdout);
#endif
scanf("%s",s+1);m=strlen(s+1);
for(int i=1;i<=m;++i)
{
S.init();res=0;
for(int j=i;j<=m;++j) S.extend(s[j]^48),ans[i][j]=res;
}
Q=IO::read();
while(Q--)
{
int l=IO::read(),r=IO::read();
IO::writeln(ans[l][r]);
}
return 0;
}
BZOJ2160 拉拉队排练
BZOJ
给定一个长度为
n
n
n的序列,将序列的所有长度为奇数的回文串按照长度从小到大排序,问前
K
K
K个串长度的乘积时多少。
n
≤
1
0
6
,
K
≤
1
0
12
n\leq 10^6,K\leq 10^{12}
n≤106,K≤1012
建出回文树,记录每个长度有哪些节点,统计一下就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10,mod=19930726;
int n;
ll K,c[N];
char s[N];
struct PAM
{
int sz,las;
int fa[N],len[N],cnt[N],ch[N][26],quick[N][26];
void init()
{
fa[0]=sz=1;len[1]=-1;
for(int i=0;i<26;++i) quick[1][i]=quick[0][i]=1;
}
void extend(int x)
{
int w=s[x]-'a',p=las,q,now;
if(s[x-len[p]-1]^s[x]) p=quick[p][w];
if(ch[p][w]) cnt[ch[p][w]]++;
else
{
q=++sz;len[q]=len[p]+2;now=fa[p];
if(s[x-len[now]-1]==s[x]) fa[q]=ch[now][w];
else fa[q]=ch[quick[now][w]][w];
memcpy(quick[q],quick[fa[q]],sizeof(quick[q]));
quick[q][s[x-len[fa[q]]]-'a']=fa[q];
ch[p][w]=q;cnt[q]=1;
}
las=ch[p][w];
}
void pushup()
{
for(int i=sz;i;--i) cnt[fa[i]]+=cnt[i];
}
}P;
ll qpow(ll x,ll y)
{
ll res=1;
for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ2160.in","r",stdin);
freopen("BZOJ2160.out","w",stdout);
#endif
scanf("%d%lld%s",&n,&K,s+1);P.init();
for(int i=1;i<=n;++i) P.extend(i);
P.pushup();
for(int i=2;i<=P.sz;++i) (c[P.len[i]]+=P.cnt[i])%=mod;
ll sum=0,ans=1;
for(int i=n;i;--i)
{
if(!(i&1)) continue;
//printf("%d %lld %lld\n",i,c[i],sum);
if(sum+c[i]>=K)
{
ans=ans*qpow(i,K-sum)%mod;sum+=c[i];
break;
}
ans=ans*qpow(i,c[i])%mod;sum+=c[i];
}
if(sum<K) puts("-1"); else printf("%lld\n",ans);
return 0;
}
Gym100548G The Problem to Slow Down You
CF
两个串的相同回文子串有多少对。
n
≤
2
×
1
0
5
n\leq 2\times 10^5
n≤2×105
建出两个回文自动机,从两个根往下
d
f
s
dfs
dfs计算即可。
一个有趣的事情是,我开始仿照了
SAM
\text{SAM}
SAM的做法,桶排后拓扑序来往上贡献,然而这样子一直
RE
\text{RE}
RE,但是直接按节点标号倒序贡献就能过。
自己十分
SB
\text{SB}
SB啊,明明树结构的构造方式都是不一样的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
ll ans;
struct PAM
{
char s[N];
int n,sz,las;
int fa[N],len[N],cnt[N],ch[N][26],quick[N][26];
void init()
{
//memset(ch,0,sizeof(ch));memset(quick,0,sizeof(quick));
///memset(fa,0,sizeof(fa));memset(len,0,sizeof(len));memset(id,0,sizeof(id));memset(cnt,0,sizeof(cnt));
//memset(id,0,sizeof(id));memset(b,0,sizeof(b));
for(int i=0;i<=sz;++i)
{
fa[i]=len[i]=cnt[i]=0;s[i]='\0';
memset(ch[i],0,sizeof(ch[i])),memset(quick[i],0,sizeof(quick[i]));
}
las=0;fa[0]=sz=1;len[1]=-1;
for(int i=0;i<26;++i) quick[0][i]=quick[1][i]=1;
}
void extend(int x)
{
int w=s[x]-'a',p=las,q,now;
if(s[x-len[p]-1]^s[x]) p=quick[p][w];
if(ch[p][w]) ++cnt[ch[p][w]];
else
{
q=++sz;len[q]=len[p]+2;now=fa[p];
if(s[x-len[now]-1]==s[x]) fa[q]=ch[now][w];
else fa[q]=ch[quick[now][w]][w];
memcpy(quick[q],quick[fa[q]],sizeof(quick[q]));
quick[q][s[x-len[fa[q]]]-'a']=fa[q];
ch[p][w]=q;cnt[q]=1;
}
las=ch[p][w];
}
void pushup()
{
/*for(int i=2;i<=sz;++i) ++b[len[i]];
for(int i=1;i<=n;++i) b[i]+=b[i-1];
for(int i=2;i<=sz;++i) id[b[len[i]]--]=i;
for(int i=sz-1;i;--i) cnt[fa[id[i]]]+=cnt[id[i]];*/
for(int i=sz;i;--i) cnt[fa[i]]+=cnt[i];//we can't use topsort?
}
void build()
{
init();scanf("%s",s+1);n=strlen(s+1);
for(int i=1;i<=n;++i) extend(i);
pushup();
//for(int i=2;i<=sz;++i) printf("%d %d\n",len[i],cnt[i]);
//puts("");
}
}P1,P2;
void dfs(int x,int y)
{
if(x>1) ans+=(ll)P1.cnt[x]*P2.cnt[y];
//printf("%d %d %d %d %d %d\n",x,y,P1.len[x],P2.len[y],P1.cnt[x],P2.cnt[y]);
for(int i=0;i<26;++i)
if(P1.ch[x][i]>1 && P2.ch[y][i]>1) dfs(P1.ch[x][i],P2.ch[y][i]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("Gym100548G.in","r",stdin);
freopen("Gym100548G.out","w",stdout);
#endif
int T;scanf("%d",&T);
for(int cas=1;cas<=T;++cas)
{
ans=0;P1.build();P2.build();
for(int i=0;i<2;++i) dfs(i,i);
printf("Case #%d: %lld\n",cas,ans);
}
return 0;
}
HDU5421 Victor and String
HDU
动态在前端插入一个字符,动态在后端插入一个字符,回答当前本质不同的回文串个数,回答当前回文串个数。
n
≤
1
0
5
n\leq 10^5
n≤105
多记录一个最长回文前缀,注意当最长前后缀相等时要让两个的
l
a
s
las
las指针相等。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll ans;
struct PAM
{
int las1,las2,l,r,sz;
int fa[N],len[N],dep[N],ch[N][26],quick[N][26];
char s[N<<1];
void init()
{
memset(s,'\0',sizeof(s));
memset(ch,0,sizeof(ch));memset(quick,0,sizeof(quick));
memset(fa,0,sizeof(fa));memset(len,0,sizeof(len));memset(dep,0,sizeof(dep));
l=N,r=l-1;las1=las2=0;sz=fa[0]=1;len[1]=-1;
for(int i=0;i<26;++i) quick[0][i]=quick[1][i]=1;
}
void extbeg(int x)
{
int w=s[x]-'a',p=las2,q,now;
if(s[x+len[p]+1]^s[x]) p=quick[p][w];
if(!ch[p][w])
{
q=++sz;len[q]=len[p]+2;now=fa[p];
if(s[x+len[now]+1]==s[x]) fa[q]=ch[now][w];
else fa[q]=ch[quick[now][w]][w];
memcpy(quick[q],quick[fa[q]],sizeof(quick[q]));
quick[q][s[x+len[fa[q]]]-'a']=fa[q];
ch[p][w]=q;dep[q]=dep[fa[q]]+1;
}
las2=ch[p][w];ans+=dep[las2];
if(len[las2]==r-l+1)las1=las2;
}
void extend(int x)
{
int w=s[x]-'a',p=las1,q,now;
if(s[x-len[p]-1]^s[x]) p=quick[p][w];
if(!ch[p][w])
{
q=++sz;len[q]=len[p]+2;now=fa[p];
if(s[x-len[now]-1]==s[x]) fa[q]=ch[now][w];
else fa[q]=ch[quick[now][w]][w];
memcpy(quick[q],quick[fa[q]],sizeof(quick[q]));
quick[q][s[x-len[fa[q]]]-'a']=fa[q];
ch[p][w]=q;dep[q]=dep[fa[q]]+1;
}
las1=ch[p][w];ans+=dep[las1];
if(len[las1]==r-l+1)las2=las1;
}
}S;
int main()
{
#ifndef ONLINE_JUDGE
freopen("HDU5421.in","r",stdin);
freopen("HDU5421.out","w",stdout);
#endif
int m;
while(~scanf("%d",&m))
{
S.init();ans=0;
while(m--)
{
int op;char c[2];
scanf("%d",&op);
if(op<=2)
{
scanf("%s",c);
if(op==1) S.s[--S.l]=c[0],S.extbeg(S.l);//pos
else S.s[++S.r]=c[0],S.extend(S.r);
}
else if(op==3) printf("%d\n",S.sz-1);
else printf("%lld\n",ans);
}
}
return 0;
}