题解 [POI2010] ANT-Antisymmetry
尝试放到PAM上,跳fail的时候将判断改成等于,但炸了半个下午
手模后发现一旦有一个元素成为odd的子节点,它就可能无法被后面的偶长度反回文串考虑了
于是认为PAM做不了
但我傻了,PAM是可以做的
因为最终的串一定是偶长度的,所以我们可以强制不让odd有子节点
当跳完fail发现现在跳到了odd时,我们可以直接将now指向even并return
那么下一个元素就可以选当前点了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
//#define int long long
int n;
char s[N];
ll ans;
int son[N][2], len[N], fail[N], cnt[N], now, tot;
void init() {tot=1; len[1]=-1; fail[0]=fail[1]=1;}
int getfail(int u, int i) {while (u!=1 && (i-len[u]-1<1||s[i-len[u]-1]==s[i])) u=fail[u]; return u;}
void insert(char c, int i) {
// cout<<"ins"<<endl;
int u=getfail(now, i), v=c-'0';
if (u==1) {now=0; return ;}
if (!son[u][v]) {
len[++tot]=len[u]+2;
int t=getfail(fail[u], i);
fail[tot]=son[t][v];
son[u][v]=tot;
// cout<<"add edge: "<<u<<' '<<v<<' '<<tot<<endl;
// cout<<"add fail: "<<tot<<' '<<fail[tot]<<endl;
}
++cnt[now=son[u][v]];
}
signed main()
{
scanf("%d%s", &n, s+1);
init();
for (int i=1; i<=n; ++i) insert(s[i], i);
for (int i=tot; i>=2; --i) {
cnt[fail[i]]+=cnt[i];
ans+=cnt[i];
}
printf("%lld\n", ans);
return 0;
}