[jzoj]3468. 【NOIP2013模拟联考7】OSU!(osu) (期望DP)

来源:互联网 发布:ecshop 2.7.3 php版本 编辑:程序博客网 时间:2024/05/18 20:36

Problem

给你一个序列,ai表示第i个数为1的概率,1ai0的概率.

在长度为n01串中,一段连续的x1,代价是x3,求代价期望.

Data constraint

30%的数据 n<=20

60%的数据 n<=1000

100%的数据 n<=100000

Solution

  • 20%

    • 这一档部分分很好拿,直接暴力即可.
  • 60%

    • 他喵的我想了很久,还是想不出来,我一直纠结于如何把概率给它乘上去.

    • 但当我再想久一点后,发现自己简直是个逗比,为什么不可以用乘法分配律呢?

    • 于是,我的想法是:

      • f[i][j]表示从第i个节点开始,已经有j个连续的1了.

      • 再设g[i][j]表示其对应的概率.

      • 然后我们就可以通过下一个点选还是不选愉快地转移了.

#include <iostream>#include <cstdio>#include <cstring>#define Maxn 100010#define Mam 1010#define fo(i,a,b) for (i = a; i <= b; i++)using namespace std;int n,i,j;long double a[Maxn],b[Maxn],f[Mam][Mam],t[Mam][Mam];int main(){    freopen("osu.in","r",stdin);    freopen("osu.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)        scanf("%Lf",&a[i]), b[i] = 1 - a[i]; b[i]=1;    t[0][0] = 1;    fo(i,0,n)    {        fo(j,0,i)        {            f[i+1][j+1] = (f[i+1][j+1] + f[i][j]) * a[i + 1];            t[i+1][j+1] = t[i+1][j+1] + t[i][j] * a[i + 1];            f[i+1][0] = f[i+1][0] + (j * j * j) * t[i][j] + f[i][j];            t[i+1][0] = t[i+1][0] + t[i][j] * b[i + 1];        }        f[i+1][0] = f[i+1][0] * b[i + 1];    }    printf("%0.1Lf",f[n+1][0]);}
  • 100%

    • 观察上述方法,其瓶颈在于j,因为我们要求一个个数次方,所以必须知道有多少个数.

    • 但如果,我们能不需要知道其个数,直接从ii+1,那么我们就可以O(n)

    • ii+1,其实我们只需要把立方给拆一下

    • zz都知道(i+1)3=i3+3i2+3i+1,所以我们记录f[i][1/2/3]分别表示以13为次方的答案.

    • 注意f[i][1/2]转移是必须选i+1的,而f[i][3]可以选或不选.

    • 有点难理解.

#include <iostream>#include <cstdio>#include <cstring>#define Maxn 100010#define fo(i,a,b) for (i = a; i <= b; i++)using namespace std;int n,i;long double a[Maxn],b[Maxn],f[Maxn][4];int main(){    freopen("osu.in","r",stdin);    freopen("osu.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)        scanf("%Lf",&a[i]), b[i] = 1 - a[i]; b[i] = 1;    fo(i,0,n)    {        f[i+1][3] = (f[i][3] + 3 * f[i][2] + 3 * f[i][1] + 1) * a[i + 1];        f[i+1][3] += (f[i][3] * b[i + 1]);        f[i+1][2] = (f[i][2] + 2 * f[i][1] + 1) * a[i + 1];        f[i+1][1] = (f[i][1] + 1) * a[i + 1];    }    printf("%0.1Lf",f[n+1][3]);}