【题解】Luogu Osu!三题 期望
打开某谷,搜索osu
Luogu P1654
Luogu CF235B
Luogu P1365
先%本机房的真·Osu!神仙 STO superminivan ORZ
三道题都差不多,就当三倍经验了
P1365 题解
大力推式子
设$f[i]$表示以$i$结尾的期望得分,$len$为期望连续的$o$的个数
分类讨论:
①当前字母为$o$时,$f[i]=f[i-1]+((len+1)^2-len^2)$ 此时$len+1$
化简 $=>$ $f[i]=f[i-1]+2*len+1$
②当前字母为$x$时,$f[i]=f[i-1]$ 此时$len=0$
③当前字母为?时,为$(①+②)/2$
也就是 $f[i]=f[i-1]+len+0.5$
整理变成$f[i]=f[i-1]+(2*len+1)*p[i]$
其中$p[i]$就是i位置出现o的期望
$o$ $p[i]=1$
$x$ $p[i]=0$
$?$ $p[i]=0.5$
再看$len$怎么维护,设$x[i]$表示$i$结尾的最后一段连续$o$的个数
同样可以转化为$x[i]=(x[i-1]+1)*p[i]$
综上,转移方程为
$$f[i]=f[i-1]+(2*x[i]+1)*p[i]$$
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int mod=1e4; 5 const int maxn=1e6+10; 6 namespace gengyf{ 7 inline int read(){ 8 int x=0,f=1;char s=getchar(); 9 while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 10 while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} 11 return f*x; 12 } 13 double f[maxn],p[maxn],x[maxn]; 14 string s;int n; 15 int main(){ 16 n=read();cin>>s; 17 for(int i=0;i<n;i++){ 18 if(s[i]=='o')p[i+1]=1.0; 19 if(s[i]=='x')p[i+1]=0.0; 20 if(s[i]=='?')p[i+1]=0.5; 21 } 22 for(int i=1;i<=n;i++){ 23 f[i]=f[i-1]+(x[i-1]*2+1.0)*p[i]; 24 x[i]=(x[i-1]+1.0)*p[i]; 25 } 26 printf("%.4lf",f[n]); 27 return 0; 28 } 29 /* 30 aggressive 有进取心的 31 alert 机敏的 32 alliance 联盟 33 alter 修改 34 */ 35 } 36 signed main(){ 37 gengyf::main(); 38 return 0; 39 }
CF235B
没有$?$且给出出现不同字符的概率,方程同上
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int mod=1e4; 5 const int maxn=1e6+10; 6 namespace gengyf{ 7 inline int read(){ 8 int x=0,f=1;char s=getchar(); 9 while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 10 while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} 11 return f*x; 12 } 13 double f[maxn],p[maxn],x[maxn]; 14 string s;int n; 15 int main(){ 16 n=read(); 17 for(int i=1;i<=n;i++){ 18 scanf("%lf",&p[i]); 19 f[i]=f[i-1]+(x[i-1]*2+1.0)*p[i]; 20 x[i]=(x[i-1]+1.0)*p[i]; 21 } 22 printf("%.15lf",f[n]); 23 return 0; 24 } 25 /* 26 aggressive 有进取心的 27 alert 机敏的 28 alliance 联盟 29 alter 修改 30 */ 31 } 32 signed main(){ 33 gengyf::main(); 34 return 0; 35 }
P1654
没有$?$,平方变成三次方
我:这还不简单,把$(len+1)^2-len^2$改成$(len+1)^3-len^3$不就行了
???怎么连样例都没过
蒟蒻眉头一皱发现事情并不简单
重新推一下式子:
$f[i]=f[i-1]+((len+1)^3-len^3)$ $=>$ $f[i]=f[i-1]+3*(len^2+len)+1$
发现化简后的式子里既有二次项也有一次项
需要分别维护
$x[i]$表示一次项的期望,$y[i]$表示二次项的期望
code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int mod=1e4; 5 const int maxn=1e6+10; 6 namespace gengyf{ 7 inline int read(){ 8 int x=0,f=1;char s=getchar(); 9 while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 10 while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} 11 return f*x; 12 } 13 double f[maxn],p[maxn],x[maxn],y[maxn]; 14 string s;int n; 15 int main(){ 16 n=read(); 17 for(int i=1;i<=n;i++){ 18 scanf("%lf",&p[i]); 19 x[i]=(x[i-1]+1.0)*p[i]; 20 y[i]=(y[i-1]+2.0*x[i-1]+1)*p[i]; 21 f[i]=f[i-1]+(3.0*(y[i-1]+x[i-1])+1)*p[i]; 22 } 23 printf("%.1lf",f[n]); 24 return 0; 25 } 26 /* 27 aggressive 有进取心的 28 alert 机敏的 29 alliance 联盟 30 alter 修改 31 */ 32 } 33 signed main(){ 34 gengyf::main(); 35 return 0; 36 }