CF1202 - E. You Are Given Some Strings...(AC自动机)

题目链接

题意

1个匹配串 T T T n n n个模式串 S S S,求 ∑ i = 1 n ∑ j = 1 n F ( T , S i + S j ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}F(T,S_i+S_j) i=1nj=1nF(T,Si+Sj) F ( S , T ) F(S, T) F(S,T)表示T在S中出现的次数。

思路

F F F函数可以用 A C AC AC自动机来找,但是枚举所有的 < i , j > <i, j> <i,j>复杂度过高,可以建两个 A C AC AC自动机,一个正向一个反向。 d f s dfs dfs预处理每个节点的匹配情况,枚举两个串的结合点。

#include 
const int maxn = 2e5 + 5;
using namespace std;
struct Trie{
    int nex[maxn][26], fail[maxn], end[maxn];
    int root, p;
    inline int newnode() {
        for (int i = 0; i < 26; ++i) {
            nex[p][i] = -1;
        }
        end[p++] = 0;
        return p - 1;
    }
    inline void init() {
    	p = 0;
    	root = newnode();
    }
    inline void insert(char *buf) {
        int now = root;
        for (int i = 0; buf[i]; ++i) {
            if (nex[now][buf[i]-'a'] == -1) 
                nex[now][buf[i]-'a'] = newnode();
            now = nex[now][buf[i]-'a'];
        }
        end[now]++;
    } 
    inline void build() {
        queue<int> que;
        fail[root] = root;
        for (int i = 0; i < 26; ++i) {
            if (nex[root][i] == -1)
                nex[root][i] = root;
            else {
                fail[nex[root][i]] = root;
                que.push(nex[root][i]);
            }
        }
        while (!que.empty()) {
            int now = que.front();
            que.pop();
            for (int i = 0; i < 26; ++i) {
                if (nex[now][i] == -1) 
                    nex[now][i] = nex[fail[now]][i];
                else {
                    fail[nex[now][i]] = nex[fail[now]][i];
                    que.push(nex[now][i]);
                }
            }
        }
    }
    long long num[maxn], dp[maxn]; // num记录节点i匹配的个数, dp辅助得到所有适配数量
    long long dfs(int now) {
    	if (now == root) return 0;
    	if (dp[now] != -1) return dp[now];
    	return dp[now] = end[now] + dfs(fail[now]);
    }
 	inline void solve(char *buf) { 
    	fill(num, num+maxn, 0);
    	fill(dp, dp+maxn, -1);
        int now = root;
        for (int i = 0; buf[i]; ++i) {
            now = nex[now][buf[i]-'a'];
            num[i] = dfs(now);
        }	
    }
    inline long long query(char *buf) {
        int now = root;
        long long cnt = 0;
        for (int i = 0; buf[i]; ++i) {
            now = nex[now][buf[i]-'a'];
            int tmp = now;
            while (tmp != root && end[tmp] != -1) {
                cnt += end[tmp];
                end[tmp] = -1; // 统计种类,加速
                tmp = fail[tmp];
            }
        }
        return cnt;
    }
}L, R;

char s[maxn], t[maxn];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	scanf("%s", s);
	int lens = strlen(s);
	int n;
	scanf("%d", &n);
	L.init();
	R.init();
	while (n--) {
		scanf("%s", t);
		L.insert(t);
		int lent = strlen(t);
		reverse(t, t+lent);
		R.insert(t);
	}
	L.build(); R.build();
	L.solve(s);
	reverse(s, s+lens); R.solve(s);
	long long ans = 0;
	for (int i = 0; i < lens-1; ++i) {
		ans += L.num[i] * R.num[lens-2-i];
	}
	printf("%lld\n", ans);
	return 0;
}

你可能感兴趣的:(字符串,练习)