牛客__小H和遺蹟

鏈接:https://ac.nowcoder.com/acm/problem/15160
來源:牛客網
 

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述

    小H在一片遺蹟中發現了一種古老而神祕的文字,這種文字也由26種字母組成,小H用小寫字母來代替它們。遺蹟裏總共有N句話,由於年代久遠,每句話至少有一處無法辨識,用#表示,缺失的可能是任意長度(也包括0)的任意字符串。
    小H發現這些話非常相似,現在小H想知道,有多少對句子可能是相同的
    注意:(x,x)這樣的句子對不計入答案,(x,y),(y,x)視爲同一個句子對(詳見樣例)

輸入描述:

第1行,一個整數N
第2~N+1行,每行一個字符串表示一句話
2≤N≤500,000,所有字符串的總長不超過1,000,000

輸出描述:

一行,一個整數,表示你給出的答案

示例1

輸入

複製

2 
a#a 
#

輸出

複製

1

備註:

#表示任意長度的任意字符串

題意:給n個字符串,由小寫字母組成,其中有#,代表的意思可以換爲任意串,然後詢問有多少對字符串是一樣的,也就是把字符串中的#號換成字符串之後,該字符串與其他字符串相同就算爲一對,順序無關

題解:可以建兩棵tire樹,一棵是字符串開頭建立,遇到#號就跳出,另外一棵是從後面往前面走,同一個字符串是在同一時間建建立的,這樣就可以將從後面建立的和前面建立的聯繫在一起,然後先拓撲排序下從前面開始建立的,然後根據拓撲序,利用樹狀數組就可以快速得出答案,其中無非就是求,對於當前遍歷到的順序建樹的結點,找他前綴的個數和他滿足的後綴的個數,看代碼很容易就能想到

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 1e6+9;

char s[maxn];

int id(char s){
    return s-'a';
}

struct tire{
    int cnt;
    int _next[maxn][26];
    int insert(char s[]){
        int p=0;
        for(int i=0;s[i];i++){
            if(s[i]=='#')break;
            if(!_next[p][id(s[i])]){
                _next[p][id(s[i])]=++cnt;
            }
            p=_next[p][id(s[i])];
        }
        return p;
    }
}T1,T2;

struct BIT{
    int bit[maxn];
    int n=1e6;
    void add(int x,int y){
        while(x<=n){
            bit[x]+=y;
            x+=(x&-x);
        }
    }
    ll query(int x){
        ll ans=0;
        while(x){
            ans+=bit[x];
            x-=(x&-x);
        }
        return ans;
    }
}T3,T4;

vector<int>G[maxn];

int dfn;
int be[maxn],en[maxn];

void dfs1(int u){
    be[u]=++dfn;
    for(int i=0;i<26;i++){
        if(T1._next[u][i]){
            dfs1(T1._next[u][i]);
        }
    }
    en[u]=dfn;
}

ll ans=0;

void dfs2(int u){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        ans+=T3.query(be[v]);
        T3.add(be[v],1);
        T3.add(en[v]+1,-1);
        ans+=T4.query(en[v])-T4.query(be[v]);
        T4.add(be[v],1);
    }
    for(int i=0;i<26;i++){
        if(T2._next[u][i]){
            dfs2(T2._next[u][i]);
        }
    }
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        T3.add(be[v],-1);
        T3.add(en[v]+1,1);
        T4.add(be[v],-1);
    }

}

int main(){
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%s",s);
        int len=strlen(s);
        int x=T1.insert(s);
        reverse(s,s+len);
        int y=T2.insert(s);
        G[y].push_back(x);
    }
    dfs1(0);
    dfs2(0);
    printf("%lld\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章