Codeforces Round #519D. Mysterious Crime(模拟+递推)

本文介绍了一种高效算法,用于计算给定多个字符串中的公共子串总数。通过利用字符串排列特性,只需判断特定子串的存在性,便可推导出所有可能的公共子串。算法使用后缀数组和LCP技术,结合动态规划思想,从前向后遍历字符串,有效减少了计算复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意

有m个长度为n的串,问其中公共的子串一共有多少个。

题解

这题第一想法是用后缀数组lcp暴力计数,但这样不是爆内存就是爆时间……仔细观察可以发现,每个序列都是一个 1 ∼ n 1\sim n 1n的排列,我们可以以第一个串为样式,将第一个串中的所有子串枚举出来,然后依次判断,这里枚举需要一个技巧。

假设第一个串的 s [ i + 1 , i + 2 ] s[i+1,i+2] s[i+1,i+2]在每个串中都出现,那么如果 s [ i , i + 1 ] s[i,i+1] s[i,i+1]在每个串中都出现的话, s [ i , i + 2 ] s[i,i+2] s[i,i+2]也都出现过。(注意这是一个排列,所以在每个串中每个数仅出现一次)

同理 s [ i , i + 2 ] s[i,i+2] s[i,i+2]如果都出现的话,当 s [ i − 1 , i ] s[i-1,i] s[i1,i]都出现的话,那么 s [ i − 1 , i + 2 ] s[i-1,i+2] s[i1,i+2]也都出现。 以此类推,我们发现只要判断每个 s [ k , k + 1 ] s[k,k+1] s[k,k+1]是否出现就可以推出所有的情况。
从后往前做即可。
我们可以很容易的用一个 p o s [ i ] [ j ] pos[i][j] pos[i][j]记录在第 i i i个串中,数字 j j j出现的位置。现在我们从后往前枚举第一个串的每个数字,用¥len[i]记录串 [ i , n ] , [ i + 1 , n ] … [ n , n ] [i,n],[i+1,n]\dots [n,n] [i,n],[i+1,n][n,n]出现的次数,比如12345,我们先考虑数字5,这肯定在所有串中都出现,所以 l e n [ 5 ] = 1 len[5] = 1 len[5]=1,现在考虑数字4,如果45都出现,那么就相当于加上5出现次数和4的次数,即 l e n [ 4 ] = l e n [ 5 ] + 1 len[4] = len[5]+1 len[4]=len[5]+1,再考虑数字3,如果34成立,那么345肯定成立,所以一旦34成立,那么相当于4出现的次数加上5出现的次数再上上3出现的次数len[3] = len[4]+1,否则len[3] = 1。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;

int a[15][maxn], pos[15][maxn];
int len[maxn];
int main() {
	int n,m;
	scanf("%d%d", &n, &m);
	for(int i = 0; i < m; ++i)
		for(int j = 1; j <= n; ++j) {
			scanf("%d", &a[i][j]);
			pos[i][a[i][j]] = j;
		}
	long long ans = 0;
	for(int i = n; i >= 1; --i) {
		len[i] = 1;
		bool ok = true;
		for(int j = 1; j < m; ++j) {
			int p = pos[j][a[0][i]];
			if(p+1 > n || i+1 > n || a[j][p+1] != a[0][i+1])
				ok = false;
		}
		if(ok) len[i] = len[i+1]+1;
		// cout << len[i] << endl;
		ans += len[i];
	}
	printf("%lld\n", ans);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值