P5496 【模板】回文自动机(PAM)
程序员文章站
2024-03-09 08:59:41
...
题目背景
模板题,无背景(其实是我想不出背景)。
题目描述
给定一个字符串 s。保证每个字符为小写字母。对于 s 的每个位置,请求出以该位置结尾的回文子串个数。
这个字符串被进行了加密,除了第一个字符,其他字符都需要通过上一个位置的答案来解密。
具体地,若第 ii(i≥1) 个位置的答案是 k,第 i+1 个字符读入时的 ASCII 码为 c,则第 i+1 个字符实际的 ASCII 码为 (c−97+k)mod26+97。所有字符在加密前后都为小写字母。
输入格式
一行一个字符串 s 表示被加密后的串。
输出格式
一行, ∣s∣ 个整数。第 i个整数表示原串以第 i个字符结尾的回文子串个数。
输入输出样例
输入 #1
debber
输出 #1
1 1 1 2 1 1
输入 #2
lwk
输出 #2
1 1 2
输入 #3
lxl
输出 #3复制
1 1 1
说明/提示
对于 100% 的数据, 1≤∣s∣≤5×10^5
理解了PAM,这题真的很简单了
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxx 500005
#define N 26
using namespace std;
typedef long long ll;
int ans[maxx],tot;
struct PAM
{
int nex[maxx][N];
int fail[maxx];
int cnt[maxx];
int num[maxx];
int len[maxx];
int S[maxx];
int last;
int n;
int p;
inline int newNode(int l)//if single case
{
//for(int i=0;i<26;i++)nex[p][i]=0;
//cnt[p]=0;
//num[p]=0;
len[p]=l;
return p++;
}
void init()
{
p=0;
newNode(0);newNode(-1);
last=0;n=0;
S[n]=-1;
fail[0]=1;
}
inline int getFail(int x)
{
while(S[n-len[x]-1]!=S[n])x=fail[x];
return x;
}
inline void insert(int c)
{
c-='a';
S[++n]=c;
int cur=getFail(last);
if(!nex[cur][c])
{
int now=newNode(len[cur]+2);
fail[now]=nex[getFail(fail[cur])][c];
nex[cur][c]=now;
num[now]=num[fail[now]]+1;
}
last=nex[cur][c];
ans[tot++]=num[last];
cnt[last]++;
}
void count()
{
for(int i=p;i>=0;i--)cnt[fail[i]]+=cnt[i];
}
}pam;
char c[maxx];
int main()
{
scanf("%s",c);
pam.init();
pam.insert(c[0]);
for(int i=1;c[i];i++)
{
int _c=(c[i]-'a'+ans[i-1])%26+'a';
pam.insert(_c);
}
printf("%d",ans[0]);
for(int i=1;i<tot;i++)printf(" %d",ans[i]);
printf("\n");
return 0;
}
上一篇: centos7防火墙常用命令
下一篇: P5496 【模板】回文自动机(PAM)