列表

详情


NC205558. 时之魔法

描述

吉他君的乐谱上有 n 个由小写字母组成的字符串,第 i 个字符串长度为 len_i
这 n 个字符串一共有 后缀(重复算多个后缀),现在键盘手定义主唱随着乐谱上的伴奏歌唱发动的魔法值是:
其中 suf_i, suf_j 分别是 个后缀中的一个后缀,i, j 可以相同, 是这两个后缀的最长公共前缀的长度。
由于这是属于三个人的歌曲,所以乐谱上的字符串会有几率发生一些变动。其中,第 i 个字符串会有 p_i 的概率反转,现在请你求出最终发动的魔法值在模 998244353 意义下的期望。

输入描述

第一行一个数 n ,表示乐谱上字符串的个数。
第二行,共 n 个 [0,998244352] 之间的数,p_i ,表示第 i 个字符串反转的概率在模 998244353 意义下的值。
第三行到第 n+2 行,每行若干个字符,第 i 行表示第 i-2 个字符串。

输出描述

一个数,表示题意中终发动的魔法值在模 998244353 意义下的期望。

示例1

输入:

2
0 0
aaa
abb

输出:

28

说明:

对于第一个样例,所有串都没有概率反转,所以:
对于第一个串中的后缀 a:
|lcp(a,a)|=1, |lcp(a,aa)|=1,|lcp(a,aaa)|=1,|lcp(a,abb)|=1,贡献为 4。
对于第一个串中的后缀 aa :
|lcp(aa,a)|=1, |lcp(aa,aa)|=2,|lcp(aa,aaa)|=2,|lcp(aa,abb)|=1, 贡献为 6
对于第一个串中的后缀 aaa:
|lcp(aaa,a)|=1, |lcp(aaa,aa)|=2,|lcp(aaa,aaa)|=3,|lcp(aaa,abb)|=1,贡献为 7。
对于第二个串中的后缀 b:
|lcp(b,b)|=1, |lcp(b, bb)|=1, 贡献为 2。


示例2

输入:

3
166374059 332748118 499122177
abcbdea
eeaadbc
aaabb

输出:

110916194

说明:

无可奉告

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 2017ms, 内存消耗: 743972K, 提交时间: 2020-10-10 08:05:02

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mo 998244353
#define N 4000010
int t[N][26],ff[N],len[N],la,ct,n,p[N],le[N],f[N],ans,id[N],vt[N],rv[N];
char *s[N],te[N];
vector<int>g[N];
void init(){
	for(int i=1;i<=ct;i++){
		memset(t[i],0,sizeof(t[i]));
		ff[i]=len[i]=f[i]=0;
		g[i].clear();
	}
	ct=la=1;
}
int add(int c,int la,int v){
	int cur=++ct,p=la;
	len[cur]=len[la]+1;
	for(;p&&!t[p][c];p=ff[p])
		t[p][c]=cur;
	if(!p)
		ff[cur]=1;
	else{
		int q=t[p][c];
		if(len[p]+1==len[q])
			ff[cur]=q;
		else{
			int cl=++ct;
			len[cl]=len[p]+1;
			memcpy(t[cl],t[q],sizeof(t[q]));
			ff[cl]=ff[q];
			ff[cur]=ff[q]=cl;
			for(;t[p][c]==q;p=ff[p])
				t[p][c]=cl;
		}
	}
	f[cur]=(f[cur]+v)%mo;
	return cur;
}
void gt(){
	for(int i=2;i<=ct;i++)
		g[ff[i]].push_back(i);
}
void dfs(int x,int t){
	for(int y:g[x]){
		dfs(y,t);
		f[x]=(f[x]+f[y])%mo;
	}
	ans=(ans+((t+mo)%mo)*f[x]%mo*f[x]%mo*(len[x]-len[ff[x]]+mo)%mo)%mo;
}
int cp(int x,int y){
	return le[x]<le[y];
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&p[i]);
		p[i]=(1-p[i]+mo)%mo;
		id[i]=i;
	}
	for(int i=1;i<=n;i++){
		scanf("%s",te+1);
		le[i]=strlen(te+1);
		s[i]=new char[le[i]+2];
		for(int j=1;j<=le[i];j++)
			s[i][j]=te[j];
		vt[i]=rv[i]=1;
	}
	sort(id+1,id+n+1,cp);
	init();
	for(int i=1;i<=le[id[n]];i++)
		for(int j=n;j;j--){
			int x=id[j];
			if(le[x]<i)
				break;
			vt[x]=add(s[x][i]-'a',vt[x],p[x]);
			rv[x]=add(s[x][le[x]-i+1]-'a',rv[x],(1-p[x]+mo)%mo);
		}
	gt();
	dfs(1,1);
	for(int i=1;i<=n;i++){
		vt[i]=rv[i]=1;
		init();
		for(int j=1;j<=le[i];j++){
			vt[i]=add(s[i][j]-'a',vt[i],p[i]);
			rv[i]=add(s[i][le[i]-j+1]-'a',rv[i],(1-p[i]+mo)%mo);
		}
		gt();
		dfs(1,-1);
	}
	for(int i=1;i<=n;i++){
		init();
		vt[i]=1;
		for(int j=1;j<=le[i];j++)
			vt[i]=add(s[i][j]-'a',vt[i],1);
		gt();
		dfs(1,1);
	}
	printf("%lld\n",ans);
}

上一题