1. 程式人生 > 其它 >題解 [POI2010]ANT-Antisymmetry

題解 [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;
}