zoukankan      html  css  js  c++  java
  • 概率DP A1295 necklace

    试题来源
      清华大学2011年百名信息学优秀高中学子夏令营
    问题描述
      有人打算送给你一条宝石项链,包含了N颗五颜六色(一共有M种颜色)的宝石。因为本问题中你只关心每个宝石的颜色,而且项链现在两头还没有接在一起,它可以被看成是一个数字串。
      你希望在五颜六色的宝石中看到连续的一段同色宝石。因此,你定义一根宝石项链的幸运度是它最长的由同色宝石构成的连续子串的长度。 比如,项链112322211的幸运度是3,因为它包括了由同色宝石构成的子串222。而首尾的两个11并不构成连续1111,因为这个项链现在是串形的而不是环形的。
      然而,你还没有见到这个项链。你只知道每个宝石是每种颜色的概率。并且,已知每个宝石的颜色分布是独立的。现在你希望在真的见到这条项链之前计算一下,这条项链的幸运度的期望是多少?
    输入格式
      输入的第一行有两个正整数N和M。
      后面N行每行有M个非负实数。其中第i行第j列的数P_(i,j)含义是第i个宝石是颜色j的概率是P_(i,j)。每行的M个实数保证和为1。
    输出格式
      一个实数,即这条项链的幸运度的期望。四舍五入至小数点后6位。
    样例输入
    4 2
    1.0 0.0
    0.5 0.5
    0.0 1.0
    0.5 0.5
    样例输出
    2.250000
    样例说明
      我们用1和2来分别表示两种颜色的宝石,则这串项链有四种等概率的情形:1121,1122,1221和1222。它们的幸运度分别是2,2,2,3,因此期望的幸运度是2.25。
    数据规模和约定
      30%的数据满足N≤16,M≤3。
      60%的数据满足N≤100。
      100%的数据满足2≤N≤1000,2≤M≤10。

    设 p[i][j]是第j个数在第i位的概率。
    设 f[i][j][k]表示到第i位,最长长度为j,末位为k的概率。
    设 g[i][j][k]表示从i位到第j位连续为k的概率
    设 s[i][j]表示第i位最长长度为j概率之和。

    我们转移时只要考虑会不会产生长度为j+1的连续k就好了(其他不合法情况已经排除了)也就是说不合法情况只有i-j~i位上都是k.而i-j-1位上不是。
    那么怎么算不合法情况很明显了:(s[i-j-1][j]-f[i-j-1][j][k])*g[i-j][j][k]
    转移方程就是 f[i][j][k]=s[i-1][j]*a[i][k]-(s[i-j-1][j]-f[i-j-1][j][k])*g[i-j][j][k]

    注意:初始化s[0][0~n]都是1,而且j要循环到n,虽然当前f[i][j][k]不会有贡献,但后面做减法时可能会用到,但是用前缀和s减的,所以j要一直更新到n

    #pragma GCC optimize("O3")
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #define N 100005
    using namespace std;
    int n,m;
    double a[11][1005],s[1010][1010],g[11][1010][1010],f[12][1100][1100],ans;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%lf",&a[j][i]);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                g[i][j][j]=a[i][j];
                for(int k=j+1;k<=n;k++)
                    g[i][j][k]=g[i][j][k-1]*a[i][k];
            }
        s[0][0]=1;
        for(int i=1;i<=n;i++)s[0][i]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=m;k++)
                {
                    f[k][i][j]=s[i-1][j]*a[k][i];
                    if(i-j-1>=0)f[k][i][j]-=(s[i-j-1][j]-f[k][i-j-1][j])*g[k][i-j][i];
                    s[i][j]+=f[k][i][j];
                }
        for(int i=1;i<=n;i++)
            ans+=(double)(s[n][i]-s[n][i-1])*i;
        printf("%.5lf",ans);
    }
  • 相关阅读:
    缓存
    mybatis(ibatis)理解
    hibernate理解
    linux vi 命令
    Activity中ConfigChanges属性的用法
    sendStickyBroadcast和sendStickyOrderedBroadcast
    广播 BroadCastReceiver
    Android四大基本组件介绍与生命周期
    ubuntu14.04 开机自动运行应用程序
    Android中BindService方式使用的理解
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7643082.html
Copyright © 2011-2022 走看看