bzoj3450 Tyvj1952 Easy

传送门


个人认为这道题和收集邮票或多或少有相似的地方。
它们都有一个特点,就是某一步产生的贡献和这一步的信息有关。
解决分两步:第一步,计算步长的期望。第二步,找到不同步长之间贡献差值的关系式。
切入点:先假设每一步的贡献都是11
然后递推出步长的贡献后,用找到的关系式去计算真实的贡献。


l[i]l[i]表示以第ii位结尾的连续oo的期望长度。
f[i]f[i]表示到第ii位为止的期望分数。

那么对于l[i]l[i],这一段oo对应的贡献就是l[i]2l[i]^2。(根据题中定义)

如果已知l[i1]l[i-1],假设第ii位就是oo,那么这时候有
l[i]=l[i1]+1l[i]=l[i-1]+1
当前的贡献就是
l[i]2=(l[i1]+1)2=l[i1]2+2×l[i1]+1l[i]^2=(l[i-1]+1)^2=l[i-1]^2+2\times l[i-1]+1
而原来的贡献是l[i1]2l[i-1]^2,发现这时增加了2×l[i1]+12\times l[i-1]+1。当然,如果这一位是xx贡献就是00。如果是??,就用对应情况的概率*对应情况的期望就好了。这样就可以直接递推了。

现在考虑转移。
如果当前位置为xx,那么l[i]=0,f[i]=f[i1]l[i]=0,f[i]=f[i-1]这很显然,因为这里的贡献为00

如果当前位置为oo,那么l[i]=l[i1]+1,f[i]=f[i1]+2×l[i1]+1l[i]=l[i-1]+1,f[i]=f[i-1]+2\times l[i-1]+1根据刚才推导的式子可以得出。

如果当前位置为??,那么用对应情况的概率*对应情况的期望。有xxoo两种可能。那么
f[i]=f[i1]+(2×l[i1]+1)+(0)2,l[i]=(l[i1]+1)+(0)2f[i]=f[i-1]+\frac{(2\times l[i-1]+1)+(0)}{2},l[i]=\frac{(l[i-1]+1)+(0)}{2}

最后答案就是f[n]f[n]

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
double l[maxn],f[maxn];
int n;char ch[maxn];
int main(){
	scanf("%d%s",&n,ch+1);
	for(int i=1;i<=n;++i){
		if(ch[i]=='x') f[i]=f[i-1],l[i]=0;
		if(ch[i]=='o') f[i]=f[i-1]+2.0*l[i-1]+1.0,l[i]=l[i-1]+1.0;
		if(ch[i]=='?') f[i]=f[i-1]+l[i-1]+0.5,l[i]=(l[i-1]+1.0)/2.0;
 }printf("%.4lf",f[n]); 
}

当然,2×l[i1]+1(2\times l[i-1]+1)只是一个关系的形式,只要找到关系,怎么写都可以,像下面这样。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
double l[maxn],f[maxn];
int n;char ch[maxn];
int main(){
	scanf("%d%s",&n,ch+1);
	for(int i=1;i<=n;++i){
		
		if(ch[i]=='x')
		f[i]=f[i-1],l[i]=0;
		
		if(ch[i]=='o')
		l[i]=l[i-1]+1.0,f[i]=f[i-1]-l[i-1]*l[i-1]+l[i]*l[i];
		
		if(ch[i]=='?')
		f[i]=f[i-1]+((l[i-1]+1)*(l[i-1]+1)-l[i-1]*l[i-1])/2.0,
		l[i]=(l[i-1]+1.0)/2.0;

	}printf("%.4lf",f[n]); 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章