托米的字符串

题目描述
托米有一个字符串,他经常拿出来玩。这天在英语课上,他学习了元音字母{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;
}
发布了467 篇原创文章 · 获赞 241 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104077838