题目描述
托米有一个字符串,他经常拿出来玩。这天在英语课上,他学习了元音字母{a,e,i,o,u}a,e,i,o,u以及半元音 {y}y。“这些字母是非常重要的!”,托米这样想着,“那么我如果随机取一个子串,里面元音占比期望会有多大呢?”
于是,请你求出对于托米的字符串,随机取一个子串,元音({a,e,i,o,u,y}a,e,i,o,u,y)字母占子串长度比的期望是多少。
输入描述:
读入一个长度不超过 10^610
6
的只包含小写字母的字符串,即托米的字符串。
输出描述:
输出所求的期望值,要求相对(绝对)误差不超过 10^{-6}10
−6
。
示例1
输入
复制
legilimens
输出
复制
0.446746032
一般这种全区间的解,有几种做法。单独元素算贡献,枚举某个点结尾或开始的总贡献,枚举区间长度贡献。
这道题就是枚举区间长度的贡献值。
我们令 f[i] 为区间长度为i的总元音个数。
怎么计算呢?
我们可以从长度为1开始想:长度为1就是所有元音的个数。
长度为2的时候:区间[2,n-1]的元音贡献了两次,所以我们就找到了递推式。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int vis[200],n,sum[N],f[N]; char str[N]; long double res;
signed main(){
scanf("%s",str+1); n=strlen(str+1);
vis['a']=vis['e']=vis['i']=vis['o']=vis['u']=vis['y']=1;
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+vis[str[i]];
for(int i=1;i<=n;i++) f[i]=f[i-1]+(sum[n-i+1]-sum[i-1]);
for(int i=1;i<=n;i++) res+=(long double)f[i]/i;
printf("%.10Lf\n",res*2.0/n/(n+1));
return 0;
}