2018.10.22-dtoi1554字符串函数(strfun)

题目描述:

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

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

输入:

第一行输入n(1<=n<=2*10^5),表示a和b的长度

第二行输入字符串a

第三行输入字符串b

输出:

   输出一个实数表示f(x,y)的期望,答案保留6位小数。  

样例:

题目为什么要给图片样例呢??!

算法标签:期望dp

思路:


详细的在sgx神犇里有图文并茂的介绍: https://blog.csdn.net/qq_41717018/article/details/83217701

这题总体还是很妙的,运用整体思想,我们考虑单个位置上有匹配会造成多少贡献,以下:

当i<j时,我们发现,这个字母O,由于在B的开头一定在[j-i+1,j]中,可以找到会带来1的贡献的子串,由于B的结尾一定在[j,n]中,所以在A若在此位有贡献,则A的结尾一定在[i,i+n-j]中,所以总贡献即i*(n-j+1)。

当i>j时,则类似i<j的分析,则贡献就是(n-i+1)*j。

于是在一个子串中统计前缀出现的字母i出现的位置之和,和后缀字幕出现n-pos+1之和。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define D double
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5;char a[N],b[N];int n;LL f[30][N],g[30][N],sum;
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
int main()
{
    n=read();scanf(" %s",a+1);scanf(" %s",b+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=26;j++)f[j][i]=f[j][i-1];f[a[i]-'A'+1][i]+=(LL)i;
    }
    for(int i=n;i;i--){
        for(int j=1;j<=26;j++)g[j][i]=g[j][i+1];g[a[i]-'A'+1][i]+=1ll*(n-i+1);
    }
    for(int i=1;i<=n;i++)
        sum+=(LL)i*g[b[i]-'A'+1][i+1]+1ll*(n-i+1)*f[b[i]-'A'+1][i];
    printf("%.6lf
",(D)sum*6.0/(1.0*(1.0*(D)(n+1)*(D)(2*n+1)*(D)n)));
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/9836012.html