Link
https://jzoj.net/senior/#main/show/3468
Description
osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为一个长度为n的01串。在这个串中连续的x个1可以贡献x^3的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。
Solution
我疑心这是一道极好的题目,网上的题解阐述的是大概,吾大都不懂。下面是我自个儿的理解,赘述一下。。
60分
我们发现,如果位置是0,那么对答案没有一点贡献。
答案是由一个或一段的1贡献的。所以,我们可以枚举连续的一段1的位置,使其满足它是相对独立的,没有与别段有交集。
100分
有办法可以快速处理以上的方法吗。答案使没有的。我们只能另辟途径。
看到概率,脑子里除了DP就是暴力。
循规蹈矩地设F[i]表示前i位的期望答案。
当前位选0,那么答案便是f[i-1];当前位选1,那么对答案的贡献自然就多了,设这个多出来的贡献为k。
根据上面的理解可以得到
F[i]=f[i-1]*(1-p[i])+(f[i-1]+k)*p[i]
整理可得
f[i]:=f[i-1]+贡献*p[i];
关键是贡献的如果求贡献。我们知道,每次多1,那么答案就多(x+1)3--x3=3*x2+3x+1,x显然是一个期望长度。令人蛋疼的是,期望的平方不等于平方的期望
设g1表示一次项的期望长度,g2表示二次项的期望长度。
g1相当于x,是期望长度,那么显然g1[i]=(g1[i-1]+1)*p[i]
因为(x+1)2-x2=2x+1,故可得g2[i]=(g2[i-1]+2*g1[i-1]+1)*p[i];
贡献的问题显然可得。具体见标程
Code
60分
var now,ans:extended; n,i,j:longint; a:array[0..1000] of extended; begin assign(input,'osu.in');reset(input); assign(Output,'osu.out');rewrite(output); readln(n); for i:=1 to n do readln(a[i]); for i:=1 to n do begin now:=1; for j:=1 to n-i+1 do begin now:=now*a[i+j-1]; ans:=ans+j*j*j*now*(1-a[i-1])*(1-a[i+j]); end; end; writeln(ans:0:1); end.
100分
var n,i:longint; a,f,g1,g2:array[0..100000] of extended; begin assign(input,'osu.in');reset(input); assign(Output,'osu.out');rewrite(output); readln(n); for i:=1 to n do readln(a[i]); for i:=1 to n do begin g1[i]:=(g1[i-1]+1)*a[i]; g2[i]:=(g2[i-1]+2*g1[i-1]+1)*a[i]; f[i]:=f[i-1]+(3*g2[i-1]+3*g1[i-1]+1)*a[i]; end; writeln(f[n]:0:1); end.