【LuoguP1654】OSU! 题解
写在前面
$\text{OSU!}$的嘛。。。$\text{PC}$ 端的音游确实没打过,,,主要 $\text{phigros、Cytus2、MuseDash、Arcaea}$,而且都不是很精通。。。
好了不扯了
嚯,做到这道题我终于明白期望的线性性有多重要了。。
这道题对于本蒟蒻来说是有点挑战性的,但是实际上是道水题,我就写写这道题我是如何一步一步地明白的吧!
Sourse
首先我们要明确一个点:我们每一次操作 $\text{combo}$ 要将答案累加。
那么要累加甚么呢?$E((x+d)^3) - E(x^3)$。这一次没能接上 $\text{combo}$ 就对已有的答案没有贡献 $E((x+d)^3) - E(x^3) = 0$。
这是为甚么?因为如果我们在此步操作中成功 $\text{combo}$ 了,那么我们就要处理一个连续长度为 $x+1$ 长的三次方,而又因为之前算过连续长度为 $x^3$,所以我们这里把他们相减就是我们在这一步所要累加的。
相减后:$3 \times E(x^2) + 3 \times E(x) + E(1)$ 这就是我们要累加的答案 别忘了乘上概率 $p$ (期望定义)
然后就可以对 $E(x^2)$、$E(x)$ 分别进行维护了
关于为甚么 $f_i = f_{i-1} + p \times (3 \times x2_{i-1} + 3 \times x1_{i-1} + 1)$ 中 $f_{i-1}$ 不用乘 $p$,这个就是刚才我一直解释的"累加"
还不懂的话就要学会借力!问同机房的同学或者老师!他们能给你讲通!(确信)
$\text{Code}$
代码有点丑。。。凑合着看吧~
Code
#include <iostream> #include <iomanip> #include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <algorithm> #define ll long long #define mem(x,y) memset(x,y,sizeof(x)) #define re register int #define iwh printf("我永远爱文虎") #define ot(x) printf("%d",x) #define lot(x) printf("%lld",x) #define MARK printf("~~~") #define _MARK printf("###") #define LMARK printf("@@@@@@") #define SLEEP printf("💤") #define SLEEPER printf("(~﹃~)~zZ") #define STUDY printf("📕") #define _ putchar(' ') #define endl putchar('\n') #define char_phi signed #define N 100005 using namespace std; int n; double f[N], x1[N], x2[N]; inline int read(){ int x = 0; char c; while(!isdigit(c = getchar())); do{ x = (x << 3) + (x << 1) + (c & 15); }while(isdigit(c = getchar())); return x; } void work(){ //唔 OSU的嘛...倒是没打过PC端的音游... //这两节课光搞概念和公式了,明天再打这道题吧 //(x+1)^3 = x^3 + 3*x^2 + 3*x + 1 //上厕所回来的路上想明白了 //期望具有线性性,不是吗? //所以期望完全可以分开维护 //E(x+1) = E(x) + E(1) //E((x+1)^2) = E(x^2) + 2*E(x) + E(1) //E((x+1)^3) = E(x^3) + 3*E(x^2) + 3*E(x) + E(1) //然后对于E(x^3),E(x^2),E(x)分开维护就ok了 //然后E((x+1)^3) 是对答案的贡献!感谢cjhdalao的一语点通
//又有了不明白的地方 不愧是cjh大佬,又点通了!!! //我爱cjh就像cjh爱姐姐(什) //x1[i-1],x2[i-1]需要乘p,因为他俩是纯期望推过来的!!! //f[i-1]不用乘p,是因为f[i-1]是已经算好的答案,而后面那两个才是对答案的贡献 //E((x+1)^3) - E(x^3) = 3*E(x^2) + 3*E(x) + E(1)!!!就是这里!!! //原来已经算好了,此处再算一个连续串的长度然后和之前的相减才是对答案的贡献 n = read(); double p; for(re i = 1 ; i <= n ; ++ i){ scanf("%lf",&p); x1[i] = (x1[i-1] + 1) * p; x2[i] = (x2[i-1] + 2*x1[i-1] + 1) * p; f[i] = f[i-1] + (3*x2[i-1] + 3*x1[i-1] + 1) * p;//终于弄明白了!我要写个blog纪念一下 // printf("") } printf("%.1lf",f[n]);
}
char_phi main(){
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
work();
return 0;
}