2020牛客暑期多校训练营(第二场)——A

All with Pairs

链接:https://ac.nowcoder.com/acm/contest/5667/A
来源:牛客网

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Given {n}n strings s_1, s_2, \cdots, s_ns
1

,s
2

,⋯,s
n

. Now define {f(s, t)}f(s,t) as the maximum {i}i that satisfy s_{1\dots i} = t_{|t|-i+1 \dots |t|}s
1…i

=t
∣t∣−i+1…∣t∣

, and if such {i}i doesn’t exist, {f(s, t) = 0}f(s,t)=0.
The Problem is to calculate:
\sum_{i=1}{n}\sum_{j=1}{n}f(s_i, s_j)^2 \pmod{998244353}∑
i=1
n


j=1
n

f(s
i

,s
j

)
2
(mod998244353)
输入描述:
The first line contains one integer n~(1 \leq n \leq 10^5)n (1≤n≤10
5
), denoting the number of given strings.
The following {n}n lines each contains a string s_i~(i = 1, 2, \cdots, n)s
i

(i=1,2,⋯,n).
It’s guaranteed that 1\leq |s_i|, \sum|s_i| \leq 10^61≤∣s
i

∣,∑∣s
i

∣≤10
6
and all strings only contain lowercase letters.
输出描述:
Only one line containing one integer, denoting the answer.
示例1
输入
复制
3
ab
ba
aba
输出
复制
29
题意:给定n个字符串,每一个串前缀和其他串的后缀进行匹配,计算匹配的最大长度的平方和。
题解:哈希函数预处理每一个字符串的后缀,并记录每一个哈希值,然后处理每个字符串的前缀哈希值,统计每个字符串的贡献值,但是,例如”aba“,这个字符,其前缀“a”,“aba”,会被重复统计,所以需要跑一遍kmp求出next数组,来处理掉这种重复的情况,最后计算答案即可。
由于哈希函数不经常写,忘记key值该怎么取了,wa了几次。
key应该是取较大的素数(我认为是这样)。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ll mod=998244353;
const int N=1e6+500;
const int key=131;
map<ull,int>mp;
string s[N];
int has[N];
int nex[N];
void Hash(string a) {
	ull cut=0;
	ull p=1;
	for(int i=a.size()-1; i>=0; --i) {
		cut+=p*(a[i]-'a'+1);
		p*=key;
		mp[cut]++;
	}
	return;
}
void kmp(string a,int n) {
	nex[0]=-1;
	int j=0,k=-1;
	while(j<n) {
		if(k==-1||a[k]==a[j])
			nex[++j]=++k;
		else k=nex[k];
	}
}
int main() {
	int n;
	scanf("%d",&n);
	for(int i=1; i<=n; ++i) {
		cin>>s[i];
		Hash(s[i]);
	}
	ll ans=0;
	for(int i=1; i<=n; ++i) {
		ull cut=0;
		int len=s[i].size();
		for(int j=0; j<len; ++j) {
			cut=cut*key+(s[i][j]-'a'+1);
			has[j+1]=mp[cut];
		}
		kmp(s[i],len);
		for(int j=1; j<=len; ++j) {
			has[nex[j]]-=has[j];
		}
		for(int j=1; j<=len; ++j) {
			ans=(ans+1ll*has[j]*j*j%mod)%mod;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值