bzoj3450 Tyvj1952 Easy

Tyvj1952 Easy

Time Limit: 10 Sec Memory Limit: 128 MB

Description

某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(
我们来简化一下这个游戏的规则
有n次点击要做,成功了就是o,失败了就是x,分数是按comb计算的,连续a个comb就有aa分,comb就是极大的连续o。
比如ooxxxxooooxxx,分数就是2
2+4*4=4+16=20。
Sevenkplus闲的慌就看他打了一盘,有些地方跟运气无关要么是o要么是x,有些地方o或者x各有50%的可能性,用?号来表示。
比如oo?xx就是一个可能的输入。
那么WJMZBMR这场osu的期望得分是多少呢?
比如oo?xx的话,?是o的话就是oooxx => 9,是x的话就是ooxxx => 4
期望自然就是(4+9)/2 =6.5了

Input

第一行一个整数n,表示点击的个数
接下来一个字符串,每个字符都是ox?中的一个

Output

一行一个浮点数表示答案
四舍五入到小数点后4位
如果害怕精度跪建议用long double或者extended

Sample Input

4
????

Sample Output

4.1250

n<=300000
osu很好玩的哦
WJMZBMR技术还行(雾),x基本上很少呢

这道题是真的玄学啊。
先说一下这道题的大概做法:

考虑每个位置对答案的贡献是多少。
若前面串的长度是\(len\)
若这个地方是\(o\) 那他对答案的贡献就是\((len+1)^2-len^2=2*len+1\),现在的\(len\)长就变成\(len+1\)了。
若这个地方是\(x\),那他对答案的贡献是\(0\)\(len\)长变成\(0\).
若是?,那分情况讨论:
\(0.5\)的概率是\(o\),对答案的贡献是\(2*len+1\), \(len=len+1\)
\(0.5\)的概率是\(x\),对答案的贡献是\(0\)\(len=0\)
所以\(?\)对答案的贡献是\(0.5*(2*len+1)+0.5*0\),\(len=0.5*(len+1)+0.5*0\)

那么为什么这样是对的呢?(我们必须至少自己说服自己啊233)
我们可以这样考虑:
对于每一个位置的?
设当前的长度为\(len\)(不包括这个?)
那么它有两种可能:\(len = 0\) 或者 \(len = len + 1\)
显然后面对答案的贡献和这次的选择有关系,我们设这个点以后的贡献为\(f(len)\)
由于我们已经证明了对于每一个点的贡献和len的长度是一次函数关系\((2*len+1)\),那么我们可以利用这个性质。
举个例子: 设\(g(x) = k*x + b\),那么\(g(1) + g(3) = 2 * g(2)\)(你可以理解为把\(k\)提出来,常数抵消)
所以,这个点对答案的贡献就为\(f(len + 1) + f(0) = f(\frac{1}{2}*(len + 1 + 0)) = f(0.5*len+0.5)\)
所以,我们可以用\(0.5*len+0.5\)这个平均值来代替这两个不同的情况。
那么对于当前这个点本身的贡献就更简单了\(\frac{1}{2}*(2 * len + 1) + \frac{1}{2} * 0\)
(自己说服了自己,感觉自己yy的方法很是很不错的滴)


#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
long double dp[maxn][4];
char s[maxn];
int n, lin;
double ans = 0, len = 0;

int main()
{
	scanf("%d", &n); scanf("%s", s + 1);
	for(int i = 1; i <= n; ++i)
	{
		if(s[i] == 'x'){len = 0;}
		if(s[i] == 'o'){ans += 2 * len + 1; len++;}
		if(s[i] == '?'){ans += len + 0.5; len = 0.5 * len + 0.5;}
	}	
	printf("%.4f", ans);
	return 0;
}

posted @ 2018-03-21 17:29  沛霖  阅读(171)  评论(0编辑  收藏  举报