UVA 7041 The Problem to Slow Down You (迴文樹)

The Problem to Slow Down You

After finishing his homework, our problem setter Federmann decided to kill time by hanging around online. He found a cool chat room that discusses competitive programming. Federmann has already joined lot of such chat rooms, but this one is special. Once he entered the chat room, he noticed that there is an announcement saying “We forbid off-topic messages!”. Federmann thinks that’s quite un- usual, he decided to sit down and join the talk. After watching people discussing different programming challenges for a while, he found an interesting message saying “No, Federmann won’t prepare another problem about strings this year.”
“Oh, why do you guys think about that?” Federmann smiled. “Don’t they know I have an Edward number (the Edward number is something like Erds number, among problem setters) of 3?”
He then thought about something about palindrome, given two strings A and B, what is the number of their common palindrome substrings? The amount of common palindrome substrings between two strings is defined as the number of quadruple (p, q, s, t), which satisfies that:
1. 1 ≤ p,q ≤ length(A), 1 ≤ s,t ≤ length(B), p ≤ q and s ≤ t. Here length(A) means the length of string A.
2. Ap..q = Bs..t
3. Ap..q is palindrome. (palindrome string is the string that reads the same forward or backward)
For example, (1, 3, 1, 3) and (1, 3, 3, 5) are both considered as a valid common palindrome substring between “aba” and “ababa”.
Federmann is excited about his new task, and he is just too lazy to write solutions, help him.
Input
The first line of the input gives the number of test cases, T. T test cases follow. For each test case, the first line contains a string A and the second line contains a string B. The length of A, B will not exceed 200000.
It is guaranteed the input file will be smaller than 8 MB.
Output
For each test case, output one line containing ‘Case #x: y’, where x is the test case number (starting from 1) and y is the number of common palindrome substrings of A and B.
Sample Input
3
abacab
abccab
faultydogeuniversity
hasnopalindromeatall
abbacabbaccab
youmayexpectedstrongsamplesbutnow
Sample Output
Case #1: 12
Case #2: 20
Case #3: 18

迴文樹模板題。題意是給兩個串 問子串是迴文串的有多少對。子串必須一個在串1中一個在串2中。先把第一個串的迴文樹跑出來,在這顆樹的基礎上在用串2跑。最後cnt1[i]*cnt2[i]求個和就可以過。

#include "cstring"
#include "cstdio"
#include "string.h"
#include "iostream"
#include "cmath"
using namespace std;
const int MAXN = 400005 ;
const int N = 26 ;
char str1[MAXN];
char str2[MAXN];

struct Palindromic_Tree {
    int slen,slen1;
    int next[MAXN][N] ;//next指針,next指針和字典樹類似,指向的串爲當前串兩端加上同一個字符構成
    int fail[MAXN] ;//fail指針,失配後跳轉到fail指針指向的節點
    long long cnt[MAXN] ;
    long long cnt1[MAXN] ;
    int num[MAXN] ;
    int len[MAXN] ;//len[i]表示節點i表示的迴文串的長度
    int S[MAXN] ;//存放添加的字符
    int last ;//指向上一個字符所在的節點,方便下一次add
    int n ;//字符數組指針
    int p ;//節點指針
    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 () {//初始化
        for(int i=0;i<=slen+slen1+4;i++)
        {
            cnt1[i]=cnt[i]=0;
        }

        p = 0 ;
        newnode (  0 ) ;
        newnode ( -1 ) ;
        last = 0 ;
        n = 0 ;
        S[n] = -1 ;//開頭放一個字符集中沒有的字符,減少特判
        fail[0] = 1 ;
    }
    void init1()
    {
        last=0;
        n=0;
        S[n]=-1;
        fail[n]=1;
    }
    int get_fail ( int x ) {//和KMP一樣,失配後找一個儘量最長的
        while(S[n-len[x]- 1]!= S[n])
            x = fail[x] ;
        return x ;
    }

    void add ( int c ) {
        c -= 'a' ;
        S[++ n] = c ;
        int cur = get_fail ( last ) ;//通過上一個迴文串找這個迴文串的匹配位置
        if ( !next[cur][c] ) {//如果這個迴文串沒有出現過,說明出現了一個新的本質不同的迴文串
            int now = newnode ( len[cur] + 2 ) ;//新建節點
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自動機一樣建立fail指針,以便失配後跳轉
            next[cur][c] = now ;
            num[now] = num[fail[now]] + 1 ;
        }
        last = next[cur][c] ;
        cnt[last] ++ ;
    }

    void add1(int c)
    {
        c -= 'a' ;
        S[++ n] = c ;
        int cur = get_fail ( last ) ;//通過上一個迴文串找這個迴文串的匹配位置
        if ( !next[cur][c] ) {//如果這個迴文串沒有出現過,說明出現了一個新的本質不同的迴文串
            int now = newnode ( len[cur] + 2 ) ;//新建節點
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自動機一樣建立fail指針,以便失配後跳轉
            next[cur][c] = now ;
            num[now] = num[fail[now]] + 1 ;
        }
        last = next[cur][c] ;
        cnt1[last] ++ ;

    }

    void count () {
        for ( int i = p - 1 ; i >= 0 ; -- i )
            cnt[fail[i]] += cnt[i] ;
        //父親累加兒子的cnt,因爲如果fail[v]=u,則u一定是v的子迴文串!
    }
    void count1()
    {
        for ( int i = p - 1 ; i >= 0 ; -- i )
            cnt1[fail[i]] += cnt1[i] ;
    }
} tree;

int main()
{
    int n;
    scanf("%d",&n);
    int k=1;
    while(n--)
    {
        scanf("%s%s",str1,str2);
        tree.init();
        tree.slen=strlen(str1);
        tree.slen1=strlen(str2);
        for(int i=0;i<tree.slen;i++)
            tree.add(str1[i]);
        tree.count();
        tree.init1();
        for(int i=0;i<tree.slen1;i++)
            tree.add1(str2[i]);
        tree.count1();
        long long ans=0;
        for(int i=2;i<=tree.p-1;i++)
        {
            ans+=tree.cnt[i]*tree.cnt1[i];
        }
        printf("Case #%d: %lld\n",k++,ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章