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]); 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章