题解 [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;
}
posted @ 2021-12-09 20:48  Administrator-09  阅读(11)  评论(0编辑  收藏  举报