Jzoj2934 字符串函数

两个等长的由大写英文字母构成的字符串a和b,从a中选择连续子串x,从b中选出连续子串y。

定义函数f(x,y)为满足条件xi=yi(1<=i<=|x|)的i的个数,计算f(x,y)的数学期望。(|x|=|y|)  


首先显然不能每个串暴力,我们考虑单独计算每一个字符的贡献

对于b[i],若我们找到a[j]=b[i],可以分两种情况讨论

1.i<j 那么显然,对于b的字串,开头为[1,i],可以在a中找到完全对应的[j-i+1,j],而对于a的结尾则必然为[j,n],在b中可以找到[i,i+n-j]

所以贡献就是i*j

2.i>j 情况是对称的,所以贡献是(n-i+1)*(n-j+1)


所以对于a,我们维护一个前缀和sf[i][c]表示所有j满足j<=i而且a[j]=c的j的和,和一个后缀和sb[i][c]表示所有j满足j>=i且a[j]=c的就的和

那么对于b[i],贡献就是(n-i+1)*sf[i][b[i]]+i*sb[i+1][b[i]],累加即可,最后除以总方案数

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char a[200010],b[200010]; double A=0;
int n,sf[200010][26],sb[200010][26];
int main(){
	scanf("%d%s%s",&n,a+1,b+1);
	for(int i=1;i<=n;++i){
		memcpy(sf[i],sf[i-1],26<<2);
		sf[i][a[i]-'A']=sf[i-1][a[i]-'A']+i;
	}
	for(int i=n;i;--i){
		memcpy(sb[i],sb[i+1],26<<2);
		sb[i][a[i]-'A']=sb[i+1][a[i]-'A']+(n-i+1);
	}
	for(long long i=1;i<=n;++i)
		A+=(n-i+1)*(sf[i][b[i]-'A'])+i*(sb[i+1][b[i]-'A']); //这里+1是为了防止重复计算
	printf("%.6lf
",A*6/((n+1ll)*(n*2ll+1)*n));
}


原文地址:https://www.cnblogs.com/Extended-Ash/p/9477358.html