The Preliminary Contest for ICPC Asia Xuzhou 2019 G Colorful String(迴文自動機+dfs)

這題建立一棵迴文樹,然後用dfs搜索答案,但是有一點需要注意,就是打vis的標記時,如果標記爲1,那麼在好幾個節點都對同一個字符i打過標記,此時的搜索從字符i點回溯,回到它的父親節點,搜索其它的字符,回溯的時候把vis[i]標記成0了,之前的vis[i]標記全被清空了,如果該父親的其它字符節點下,有字符i的孩子,則此時統計就會出錯。所以打vis標記的時候讓vis++,而不是標記爲0。

#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN=3e5+10;
const int N=26;

char str[MAXN];

struct PAM {
    int len[MAXN];
    int num[MAXN];
    int s[MAXN];
    int fail[MAXN];
    int next[MAXN][N];
    int cnt[MAXN];
    int last,p,n;

    int newNode(int l) {
        for (int i=0;i<N;i++) next[p][i]=0;
        cnt[p]=0;
        num[p]=0;
        len[p]=l;
        return p++;
    }

    void init() {
        n=0;
        p=0;
        last=0;
        newNode(0);
        newNode(-1);
        fail[0]=1;
        s[0]=-1;
    }

    int getFail(int x) {
        while (s[n-len[x]-1]!=s[n]) x=fail[x];
        return x;
    }

    void add(int c) {
        c-='a';
        s[++n]=c;
        int cur=getFail(last);
        if (!next[cur][c]) {
            int now=newNode(len[cur]+2);
            fail[now]=next[getFail(fail[cur])][c];
            next[cur][c]=now;
            num[now]=num[fail[now]]+1;
        }
        last=next[cur][c];
        cnt[last]++;
    }

    void count() {
        for (int i=p-1;i>=0;i--) {
            cnt[fail[i]]+=cnt[i];
        }
    }

}pt;

int vis[N];
long long ans=0;

void dfs(int x,int cnt)
{
    ans+=cnt*pt.cnt[x];
    for (int i=0;i<N;i++) {
        if (pt.next[x][i]) {
            if (!vis[i]) {
                vis[i]++;
                dfs(pt.next[x][i],cnt+1);
                vis[i]--;
            }
            else {
                dfs(pt.next[x][i],cnt);
            }
            
        }
    }
}

int main()
{
    pt.init();
    scanf("%s",str);
    for (int i=0;str[i];i++) {
        pt.add(str[i]);
    }
    pt.count();
    // printf("%d\n",pt.cnt[0]);
    dfs(0,0);
    dfs(1,0);
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章