打开某谷,搜索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

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

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

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 }
