• [CF452E]Three strings


    题目大意:给你三个字符串$A,B,C$,令$L=min(|A|,|B|,|C|)$,对每个$iin[1,L]$,求出符合$A_{[a,a+i)}=B_{[b,b+i)}=C_{[c,c+i)}$的三元组$(a,b,c)$的个数

    题解:先建一棵广义$SAM$,求出每个点可以到达的$A,B,C$的字串的个数,然后这个点贡献的值就是三个串分别的个数乘起来,发现一个点会对$[R_{fail_p+1},R_{p}]$的区间产生贡献,可以差分一下维护。

    卡点:

    C++ Code:

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #define maxn 300010
    const int mod = 1e9 + 7;
    inline void reduce(int &x) {x += x >> 31 & mod;}
    
    int n = 0x3f3f3f3f;
    int ans[maxn];
    namespace SAM {
    #define N (maxn * 3 << 1)
    	int R[N], fail[N], nxt[N][26];
    	int lst = 1, idx = 1, sz[N][3];
    
    	void append(int ch, int tg) {
    		int p = lst, np = lst = ++idx; R[np] = R[p] + 1, sz[np][tg] = 1;
    		for (; p && !nxt[p][ch]; p = fail[p]) nxt[p][ch] = np;
    		if (!p) fail[np] = 1;
    		else {
    			int q = nxt[p][ch];
    			if (R[p] + 1 == R[q]) fail[np] = q;
    			else {
    				int nq = ++idx;
    				fail[nq] = fail[q], R[nq] = R[p] + 1, fail[q] = fail[np] = nq;
    				std::copy(nxt[q], nxt[q] + 26, nxt[nq]);
    				for (; p && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
    			}
    		}
    	}
    
    	int head[N], cnt;
    	struct Edge {
    		int to, nxt;
    	} e[N];
    	inline void addedge(int a, int b) {
    		e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    	}
    
    	void dfs(int u) {
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			dfs(v);
    			sz[u][0] += sz[v][0], sz[u][1] += sz[v][1], sz[u][2] += sz[v][2];
    		}
    	}
    	void work() {
    		for (int i = 2; i <= idx; i++) addedge(fail[i], i);
    		dfs(1);
    		for (int i = 2; i <= idx; i++) {
    			int tmp = static_cast<long long> (sz[i][0]) * sz[i][1] % mod * sz[i][2] % mod;
    			reduce(ans[R[fail[i]] + 1] += tmp - mod), reduce(ans[R[i] + 1] -= tmp);
    		}
    		for (int i = 2; i <= n; i++) reduce(ans[i] += ans[i - 1] - mod);
    	}
    #undef N
    }
    
    char s[maxn];
    int main() {
    	for (int i = 0; i < 3; i++) {
    		scanf("%s", s); SAM::lst = 1;
    		n = std::min(n, static_cast<int> (strlen(s)));
    		for (char *ch = s; *ch; ++ch) SAM::append(*ch - 'a', i);
    	}
    	SAM::work();
    	for (int i = 1; i <= n; i++) {
    		printf("%d", ans[i]);
    		putchar(i == n ? '
    ' : ' ');
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    常用Linux 服务器命令--各种性能指标命令
    jenkins离线插件安装--笨方法
    Jmeter压力测试简单教程(包括服务器状态监控)
    【JMeter】JMeter使用plugins插件进行服务器性能监控
    Linux查看服务器配置常用
    Linux下内存查看命令
    【linux命令】lscpu、etc/cpuinfo详解
    Jmeter用于接口测试中【接口耦合关联的实现】
    jmeter教程--简单的做压力测试
    将字母拆分
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10164330.html
Copyright © 2020-2023  润新知