牛客__小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;
}

 

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