概率期望题目记录

这是一个懒人的记录,因为要做的题目太多,这篇部分题目就写一下思路并不会有代码

T1

[BZOJ3270]博物馆(概率+高斯消元)

思路

f[i][j]表示A在i,B在j的概率,go[i]表示从i点到相邻某一个点的概率, go[i]=1pdu[i] g o [ i ] = 1 − p d u [ i ]
那么 f(i)(j)=f(i)(j)pipj+f(x)(j)go(x)pj+f(i)(y)go(y)pi+f(x)(y)go(y)go(x) f ( i ) ( j ) = f ( i ) ( j ) p i p j + ∑ f ( x ) ( j ) g o ( x ) p j + f ( i ) ( y ) g o ( y ) p i + f ( x ) ( y ) g o ( y ) g o ( x )
其中x与i相连,y与j相连
然后n*n个方程可以跑高斯消元了
需要注意的是,方程中等式右边在同一个f里的两个点不能相等,因为一旦相等就已经结束,不会再有走到这个点的概率

T2

[BZOJ3640]JC的小苹果(概率dp+高斯消元)

思路

这样乱走的小数据无向图考虑高斯消元
f[i][j]表示在i点血量还有j的概率,
那么 f(i)(j)=f[v(i)][j+val[i]]du[v(i)] f ( i ) ( j ) = ∑ f [ v ( i ) ] [ j + v a l [ i ] ] d u [ v ( i ) ]
我们考虑根据血量一层一层倒推着解,但是当val[i]=0的时候是同一层的,那么我们可以用高斯消元了
我们建立高斯消元的系数矩阵,可以发现消耗量为0的系数矩阵是不会变的,会变的只有常数项(我们可以通过移项将不同的f[v(i)][j+val(i)]放到常数项里),这样我们不用每次建立初始消耗量为0矩阵,只需要建立一个,然后自己模拟出三角消元的过程,时间复杂度可以达到 O(n2h+2m) O ( n 2 h + 2 ∗ m )
最后还是要注意走到n点就不会再走了也不会有转移
数据可能有重边+自环坑死我。

代码

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=200;
const int M=5005;
const double eps=1e-12;
struct hh{int i;double t;}by[N] [N];
int tot,nxt[M*2],point[N],v[M*2],n,cnt[N],val[N],du[N];double a[N] [N],f[N] [10005],b[N];
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
void init()
{
    for (int i=1;i<=n;i++)
      for (int j=i+1;j<=n;j++)
        if (fabs(a[j][i])>eps)
        {
            double t=a[j][i]/a[i][i];
            for (int k=i;k<=n;k++) a[j][k]-=t*a[i][k];
            by[j][++cnt[j]].i=i;  by[j][cnt[j]].t=t;
        }
}
void gauss(int hp)
{
    for (int i=n;i>=1;i--)
    {
        f[i][hp]=b[i]/a[i][i];
        for (int j=1;j<i;j++) b[j]-=f[i][hp]*a[j][i];
    }
}
int main()
{
    int m,hp;scanf("%d%d%d",&n,&m,&hp);
    for (int i=1;i<=n;i++) scanf("%d",&val[i]);
    for (int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        addline(x,y);du[x]++;
        if (x!=y) addline(y,x),du[y]++;
    }
    for (int i=1;i<=n;i++)
    {
        a[i][i]=1;
        if (val[i]) continue;
        for (int j=point[i];j;j=nxt[j])
          if (v[j]!=n) a[i][v[j]]-=1.0/du[v[j]];
    }
    init();
    for (int i=hp;i>=1;i--)
    {
        memset(b,0,sizeof(b));
        if (i==hp) b[1]=1.0;
        for (int j=1;j<=n;j++)
          if (val[j] && i+val[j]<=hp)
          {
            for (int k=point[j];k;k=nxt[k])
              if (v[k]!=n) b[j]+=f[v[k]][i+val[j]]/(du[v[k]]*1.0);
          }
        for (int j=1;j<=n;j++)
          for (int k=1;k<=cnt[j];k++) b[j]-=b[by[j][k].i]*by[j][k].t;
        gauss(i);
    }
    double ans=0;
    for (int i=1;i<=hp;i++) ans+=f[n][i];
    printf("%.8lf",ans);
}

T3

[BZOJ1426]收集邮票(概率dp)

思路

凡凡你个奸商
我们设g(i)表示当前有i种邮票,得到n种的期望步数
那我们推一下吧,假设我们有k种邮票,设s=k/n,即再买一张买到已有的概率是s,那么再买t次可以买到新邮票的概率是s^(t-1)*(1-s)
我们现在的目的是求一下平均拿多少次能拿到一个新邮票
那么期望 =(1s)+2s(1s)+3s2(1s)+...=(1s)(1+2s+3s2+...)=(1s)E=EsE = ( 1 − s ) + 2 s ( 1 − s ) + 3 s 2 ( 1 − s ) + . . . = ( 1 − s ) ∗ ( 1 + 2 s + 3 s 2 + . . . ) = ( 1 − s ) E = E − s E

E=1+2s+3s2+... E = 1 + 2 s + 3 s 2 + . . .

sE=s+2s2+3s3+... s E = s + 2 s 2 + 3 s 3 + . . .

EsE=1+s+s2+s3+... E − s E = 1 + s + s 2 + s 3 + . . .

等比数列求和公式?
最后的期望= 1/(1s) 1 / ( 1 − s ) (因为s^INF趋近于0,所以分子为1)
也就是 =n/(nk) = n / ( n − k ) ,也就是说平均拿 n/(nk) n / ( n − k ) 次就会有一个新的邮票

推完这个我们就可以知道 g(i)=g(i+1)+nni g ( i ) = g ( i + 1 ) + n n − i g(n)=0 g ( n ) = 0

然后我们定义pr(x,i)表示买x次能从i种买到n种的概率,实际上pr(x,i)就是再买t次可以买到新邮票的概率是s^(t-1)*(1-s)
则有 g(i)=INFx=1xpr(x,i) g ( i ) = ∑ x = 1 I N F x ∗ p r ( x , i )

然后可以步入正题啦(?!)
设计状态f[i][j]表示现在有i种邮票,下一次购买需要j元,得到n种邮票的期望花费
有i/n的概率,转移到f[i][j+1],花费是j
有(n-i)/n的概率,转移到f[i+1][j+1],花费是j
那么我们可以得到状态转移 f[i][j]=j+f[i][j+1]i/n+f[i+1][j+1](ni)/n f [ i ] [ j ] = j + f [ i ] [ j + 1 ] ∗ i / n + f [ i + 1 ] [ j + 1 ] ∗ ( n − i ) / n

但是j是INF啊,所以这个递推无法进行,考虑f[i][j]和f[i][j+1]的关系

f[i][j]=x=1INF[j+(j+1)+...+(j+x1)]pr(x,i) f [ i ] [ j ] = ∑ x = 1 I N F [ j + ( j + 1 ) + . . . + ( j + x − 1 ) ] ∗ p r ( x , i )

=x=1INFx(j+j+x1)2pr(x,i) = ∑ x = 1 I N F x ∗ ( j + j + x − 1 ) 2 ∗ p r ( x , i )

并且 f[i][j+1]f[i][j]=x=1INFxpr(x,i)=g(i) f [ i ] [ j + 1 ] − f [ i ] [ j ] = ∑ x = 1 I N F x ∗ p r ( x , i ) = g ( i )

那么就可以进一步优化我们的状态转移

f[i][j]=j+f[i][j+1]in+f[i+1][j+1]nin f [ i ] [ j ] = j + f [ i ] [ j + 1 ] ∗ i n + f [ i + 1 ] [ j + 1 ] ∗ n − i n

=j+(f[i][j]+g[i])in+(f[i+1][j]+g[i+1])nin = j + ( f [ i ] [ j ] + g [ i ] ) ∗ i n + ( f [ i + 1 ] [ j ] + g [ i + 1 ] ) ∗ n − i n

然后移项得

f[i][j]=n(j+g[i]inf[i+1][j]nin+g[i+1]nin)ni f [ i ] [ j ] = n ∗ ( j + g [ i ] ∗ i n − f [ i + 1 ] [ j ] ∗ n − i n + g [ i + 1 ] ∗ n − i n ) n − i

我们要求的是f[0][1],所以对于j!=1的情况忽略,定义F[i]表示f[i][1],也就是现在有i种邮票要得到n种的期望花费
柿子又可以简化啦!

F[i]=n((F[i+1]+g[i+1])nin+g[i]in+1)ni F [ i ] = n ∗ ( ( F [ i + 1 ] + g [ i + 1 ] ) ∗ n − i n + g [ i ] ∗ i n + 1 ) n − i
而且 F[n]=0 F [ n ] = 0

至此解出F[i]和g[i]就可以递推求解了。

#include <cstdio>
using namespace std;
const int N=10005;
double f[N],g[N];
int main()
{
    int n;scanf("%d",&n);
    for (int i=n-1;i>=0;i--)
      g[i]=g[i+1]+n/(double)(n-i),f[i]=((f[i+1]+g[i+1])*(n-i)+g[i]*i+n)/(double)(n-i);
    printf("%.2lf",f[0]);
}

真·推柿两小时码码1分钟

T4

[BZOJ2707][SDOI2012]走迷宫(概率dp+高斯消元)

思路

首先这道题目所说的到不了终点不仅仅指起点终点不连通,还包括如果这条路有走到某个节点的期望并且这个节点到不了终点,那么这也是到不了的情况
转换为代码就是先tarjan缩点,然后对于出度为0的点如果S可以到达并且不是T那就GG
然后就是平常的E[i]表示i到达T的期望步数,E[T]=0
E[i]=E[v(i)]/du(i)+1 E [ i ] = ∑ E [ v ( i ) ] / d u ( i ) + 1
然后对于每一个强联通分量里的点根据拓扑倒序求出E[i]求解。
强联通分量的点与点之间再求E[i]

T5

[BZOJ2688]Green Hackenbush(博弈+概率dp)

思路

树上删边博弈:每个节点的异或值是所有的(子节点的异或值+1)的异或和;对于一棵树来说就是根节点的异或值;对于n棵树来说就是所有树的异或值,是0就先手败,1就先手胜

我们考虑一棵n个节点的二叉树有多少种形态(卡特兰数)
h[n]=n1i=0h[i]h[ni1] h [ n ] = ∑ i = 0 n − 1 h [ i ] ∗ h [ n − i − 1 ]

g[i][j]表示i个节点的二叉树异或值为j的概率
我们还是通过判断左右子树来解出 g[n][(x+1)(y+1)]=n1i=0g[h[i]][x]g[h[ni1]][y] g [ n ] [ ( x + 1 ) ∧ ( y + 1 ) ] = ∑ i = 0 n − 1 g [ h [ i ] ] [ x ] ∗ g [ h [ n − i − 1 ] ] [ y ]

f[i][j]表示前i个子树异或值为j的概率,那么
f[i][jk]=f[i1][j]g[a[i]][k] f [ i ] [ j ∧ k ] = f [ i − 1 ] [ j ] ∗ g [ a [ i ] ] [ k ]

我们最后要的答案是1-f[n][0]

T6

[POJ2096]Collecting Bugs(期望dp)

题意

一个软件有s个子系统,会产生n种bug,某人一天发现一个bug,这个bug属于一个子系统,属于一个分类。每个bug属于某个子系统的概率是1/s,属于某种分类的概率是1/n
问发现n种bug,每个子系统都发现bug的天数的期望。

思路

f[i][j]表示发现了i种bug分布在j个系统的期望天数,我们的答案就是f[n][s]
这玩意很明显可以从四个状态转移过来,我们分类讨论
f[i][j]+=(f[i1][j]+1)ninjs f [ i ] [ j ] + = ( f [ i − 1 ] [ j ] + 1 ) ∗ n − i n ∗ j s
好吧知道这样讨论就可以了,博主太懒不想写剩下的三种了

T7

[POJ2125]Check the difficulty of problems(概率dp)

题意

t支队伍,m个问题,要求每个队伍至少回答对1个问题,至少有一支队伍回答出n个或以上个问题。求事件发生的概率

思路

我们对每支队伍进行dp,f[i][j]表示现在i个问题答对了j道的概率,那么(假设答对问题的概率是p)
f[i][j]=f[i-1][j]*(1-p)+f[i-1][j-1]*p
那么我们在计算的时候用总的概率减去不合法的概率得到答案
这里总的概率指的是所有队伍答对非0问题个数的概率(1-f[m][0]),然后减去所有队伍答对[1,n-1]的题目概率

T8

[POJ3744]Scout YYF I(概率dp+矩阵乘法)

题意

在一条布满地雷的路上,你现在的起点在1处。在N个点处布有地雷,1<=N<=10。地雷点的坐标范围:[1,1e8]
每次有p的概率前进一步,1-p的概率前进2步。问顺利通过这条路的概率。就是不要走到有地雷的地方。

思路

很简单的设计出状态f[i]表示到i号点还活着的概率(有点阴森森的)
那么对于i这个点不是地雷,f[i]=f[i-1]* p+f[i-2]*(1-p)
i要是地雷f[i]=0
但是我们发现这个n很大,显然不能递推,而且我们发现这个转移的状态还是固定的,那么矩阵乘法走起
那么还有一个问题,这个路长到无限,怎么定义最后是安全的概率呢?
我们可以用1-死去的概率就是活着的概率啦,死去的概率是什么呢?是对于每颗地雷踩中他的概率。踩中一颗就GG,所以活着的概率要乘起来
为什么可以划分成n段去求呢?因为最后活着的概率是相乘的!即走到这一步的时候默认的活着的概率是1

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct mat
{
    double sq[5][5];
    void clear(){memset(sq,0,sizeof(sq));}
}f,mul;
int a[20];double p;
mat cf(mat a,mat b)
{
    mat c;c.clear();
    for (int i=1;i<=2;i++)
      for (int j=1;j<=2;j++)
        for (int k=1;k<=2;k++)
          c.sq[i][j]+=a.sq[i][k]*b.sq[k][j];
    return c;
}
double ksm(int k)
{
    mul.sq[1][1]=p; mul.sq[1][2]=1-p;
    mul.sq[2][1]=1; mul.sq[2][2]=0; 
    f.sq[1][1]=1; f.sq[2][1]=0;
    for (;k>0;k>>=1,mul=cf(mul,mul))
      if (k&1) f=cf(mul,f);
    return f.sq[1][1];
}
int main()
{
    int n;
    while (scanf("%d%lf",&n,&p)!=EOF)
    {
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        int last=1,now; double ans=1;
        for (int i=1;i<=n;i++) ans*=(1-ksm(a[i]-a[i-1]-1));
        printf("%.7lf\n",ans);
    }
}

T9

[codeforces 148D]Bag of mice(概率dp)

题意

有两个人从一个袋子里抓老鼠,w只白老鼠,b只黑老鼠,每次每人等概率的抓出一只老鼠,第二个人抓完后会等概率的跳出一只老鼠,第一个抓到白老鼠的人赢,求第一个人赢得概率。

思路

设f[i][j]表示还有i只黑老鼠,j只白老鼠的时候第一个人(A)win的概率
那么有如下情况
A选白老鼠,直接胜利,概率是 i/(i+j) i / ( i + j )
A选黑老鼠,B选白老鼠,获胜概率是0不用考虑
A选黑老鼠,B选黑老鼠,跳出一只白老鼠,获胜概率是 j(i+j)(j1)(i+j1)i(i+j2)f[i2][j1] j ( i + j ) ∗ ( j − 1 ) ( i + j − 1 ) ∗ i ( i + j − 2 ) ∗ f [ i − 2 ] [ j − 1 ]
A选黑老鼠,B选黑老鼠,跳出一只黑老鼠,获胜概率是 j(i+j)(j1)(i+j1)j2(i+j2)f[i3][j] j ( i + j ) ∗ ( j − 1 ) ( i + j − 1 ) ∗ j − 2 ( i + j − 2 ) ∗ f [ i − 3 ] [ j ]

初始化就是如果全是黑老鼠获胜率为0,全是白老鼠获胜率为1

T10

[ZOJ3329]One Person Game(期望dp+迭代)

题意

有3个筛子,分别有k1,k2,k3个面。每次掷筛子,如果三个面为指定的a,b,c,则分数置0,否则加上三个筛子的和。当总分大于等于n结束。求游戏的期望步数

思路

比较经典的题目,设f[i]表示分数为i到游戏结束的期望步数,那么f[0]就是答案
f[i]=k1+k2+k3x=1f[i+x]p[x]+f[0]p[0]+1 f [ i ] = ∑ x = 1 k 1 + k 2 + k 3 f [ i + x ] ∗ p [ x ] + f [ 0 ] ∗ p [ 0 ] + 1 ,这里p[i]表示投出i这个总和的概率,p[0]就是投出特殊情况的概率
我们可以发现每一个都含有f[0]啊,怎么求呢?高斯消元?不行太麻烦了,我们考虑用迭代

f[i]=a[i]f[0]+b[i] f [ i ] = a [ i ] ∗ f [ 0 ] + b [ i ]

f[i]=[(a[i+k]p[k]+p[0])E[0]+b[i+k]p[k]]+1 f [ i ] = ∑ [ ( a [ i + k ] ∗ p [ k ] + p [ 0 ] ) ∗ E [ 0 ] + b [ i + k ] ∗ p [ k ] ] + 1

a[i]=a[i+k]p[k]+p[0] a [ i ] = a [ i + k ] ∗ p [ k ] + p [ 0 ] b[i]=b[i+k]p[k]+1 b [ i ] = b [ i + k ] ∗ p [ k ] + 1

那么最后的答案 f[0]=b[0]/(1a[0]) f [ 0 ] = b [ 0 ] / ( 1 − a [ 0 ] )

代码

#include <cstdio>
#include <cstring>
using namespace std;
const int N=505;
double p[N],pa[N],pb[N];
int main()
{
    int T,n,k1,k2,k3, a, b, c;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
        memset(p,0,sizeof(p));
        double one=1.0/(k1*k2*k3);
        for (int i=1;i<=k1;i++)
          for (int j=1;j<=k2;j++)
            for (int k=1;k<=k3;k++)
              if (i!=a || j!=b || k!=c) p[i+j+k]+=one;
        memset(pa,0,sizeof(pa));
        memset(pb,0,sizeof(pb));
        for (int i=n;i>=0;i--)
        {
            for (int j=3;j<=k1+k2+k3 && (i+j)<=n;j++)
              pa[i]+=pa[i+j]*p[j],pb[i]+=pb[i+j]*p[j];
            pa[i]+=one; pb[i]++;
        }
        printf("%.15lf\n",pb[0]/(1.0-pa[0]));
    }
}

T11

[HDU4035]Maze(期望dp+迭代)

题意

一棵树,一个人初始在1号点。每次到达一个点,有ki的概率被杀死,并且回到1号点,有ei的概率直接逃离,然后等概率的逃到与他相邻的节点(1-ki-ei)/du[i],每次移动步数+1。 求逃出去的期望步数。

思路

和刚才那道题目很像啊,但是这个逃离的概念比较模糊,我们就设一个0点表示
依然设E[i]表示在i点逃出去的期望步数,显然E[0]=0

E[i]=(E[v(i)]+1)1kedu[i]+E[1]k+E[0]e=(E[v(i)]+1)1kedu[i]+E[1]k E [ i ] = ∑ ( E [ v ( i ) ] + 1 ) ∗ 1 − k − e d u [ i ] + E [ 1 ] ∗ k + E [ 0 ] ∗ e = ∑ ( E [ v ( i ) ] + 1 ) ∗ 1 − k − e d u [ i ] + E [ 1 ] ∗ k
而且这是一棵树,我们要利用好这个条件,我们希望通过树形dp的方式递推
为了方便我们设 p[i]=1kieidu[i] p [ i ] = 1 − k i − e i d u [ i ]
那么柿子要微微改一下: E[i]=((E[son(i)]+1)p[i])+(E[fa]+1)p[i]+E[1]k[i] E [ i ] = ∑ ( ( E [ s o n ( i ) ] + 1 ) ∗ p [ i ] ) + ( E [ f a ] + 1 ) ∗ p [ i ] + E [ 1 ] ∗ k [ i ]
如果考虑用父亲更新儿子的话,E[fa[i]]和E[1]是未知的,而E[son[i]]是已知的,我们把ta当做一个常数,根据上一个题目的经验画一下柿子
E[i]=A[i]E[fa]+B[i]E[1]+C[i] E [ i ] = A [ i ] ∗ E [ f a ] + B [ i ] ∗ E [ 1 ] + C [ i ]
然后学着上一个题目带进去,可以得到

E[i]=(A[son(i)]E[i]+B[son(i)]E[1]+C[son(i)]+1)p[i]+(E[fa]+1)p[i]+E[1]k E [ i ] = ∑ ( A [ s o n ( i ) ] ∗ E [ i ] + B [ s o n ( i ) ] ∗ E [ 1 ] + C [ s o n ( i ) ] + 1 ) ∗ p [ i ] + ( E [ f a ] + 1 ) ∗ p [ i ] + E [ 1 ] ∗ k

(1A[son(i)]p[i])E[i]=p[i]E[fa]+(k[i]+B[son(i)]p[i])E[1]+(C[son(i)]+1)p[i]+p[i] ( 1 − ∑ A [ s o n ( i ) ] ∗ p [ i ] ) ∗ E [ i ] = p [ i ] ∗ E [ f a ] + ( k [ i ] + ∑ B [ s o n ( i ) ] ∗ p [ i ] ) ∗ E [ 1 ] + ∑ ( C [ s o n ( i ) ] + 1 ) ∗ p [ i ] + p [ i ]

那么我们设 T[i]=1A[son(i)]p[i] T [ i ] = 1 − ∑ A [ s o n ( i ) ] ∗ p [ i ] ,然后可以得到 A[i]=p[i]T[i] A [ i ] = p [ i ] T [ i ] B[i]=k[i]+B[son(i)]p[i]T[i] B [ i ] = k [ i ] + ∑ B [ s o n ( i ) ] ∗ p [ i ] T [ i ] C[i]=C[son(i)]p[i]+du[i]p[i]T[i] C [ i ] = ∑ C [ s o n ( i ) ] ∗ p [ i ] + d u [ i ] ∗ p [ i ] T [ i ] ,到这里一遍树形dp可以求出A[1],B[1],C[1]
我们要的答案是E[1],而1节点没有父亲,所以 E[1]=B[1]E[1]+C[1] E [ 1 ] = B [ 1 ] ∗ E [ 1 ] + C [ 1 ] E[1]=C[1]1B[1] E [ 1 ] = C [ 1 ] 1 − B [ 1 ]
分母为0则impossible
初始化的话,对于一个叶子结点来说 E[i]=(E[fa]+1)p[i]+E[1]k[i] E [ i ] = ( E [ f a ] + 1 ) ∗ p [ i ] + E [ 1 ] ∗ k [ i ] ,则 A[i]=p[i] A [ i ] = p [ i ] B[i]=k[i] B [ i ] = k [ i ] C[i]=p[i] C [ i ] = p [ i ]

T10&11小结

我们对于这种数据范围不适合高斯消元却用到了前面的状态的柿子,可以考虑用迭代解决,把柿子转化为a*f[前状态1]+b*f[前状态2]+常数这种样子,再代入原柿子的[可递推项]运用系数的转化去完成

<script type="math/tex; mode=display" id="MathJax-Element-56"></script>

T12

[codefoces453A]Little Pony and Expected Maximum(概率期望dp)

思路

f[i]表示i为最大值的概率,那么ans+=f[i]*i
f[i]=(im)n(i1m)n f [ i ] = ( i m ) n − ( i − 1 m ) n
表示这n种都选择1-i的数字减去都选择1-i-1之内的数字,这种容斥的思想是很常见的

T13

[codefoces498B]Name That Tune(概率dp)

题意

有n首歌,顺序播放。只有第i首歌被辨认出,才能播放第i+1首歌。对于每首歌有两个值pi,ti。表示在播放1..ti-1的时间内有pi/100的概率猜出这首歌,如果播放了ti分钟,那么一定可以辨认出。问播放时间为T,辨认出歌的数量的期望。

思路

f[i][j] f [ i ] [ j ] 表示第j秒该听第i首歌的概率,即已经听出第i-1首歌的概率。
f[i][j+1]+=f[i][j](1p[i]) f [ i ] [ j + 1 ] + = f [ i ] [ j ] ∗ ( 1 − p [ i ] )
f[i+1][j+1]+=f[i][j]p[i] f [ i + 1 ] [ j + 1 ] + = f [ i ] [ j ] ∗ p [ i ]
这样子有一种情况是错误的,就是 f[i][j] f [ i ] [ j ] 经过 t[i] t [ i ] 的时间会转移到 f[i][j+t[i]] f [ i ] [ j + t [ i ] ]
但是实际上应该转移到的是 f[i+1][j+t[i]] f [ i + 1 ] [ j + t [ i ] ]
那么这种情况特殊算一下就可以了。
ans=n+1i=2f[i][m](i1) a n s = ∑ i = 2 n + 1 f [ i ] [ m ] ∗ ( i − 1 )

T14

[codefoces698C]LRU(概率dp+状压)

题意

有一个大小为k的缓存区,每次从n种物品中按照一定的概率选取一种物品尝试放进去.同一个物品每一次选取的概率都是相同的.如果这种物品已经放进去过就不再放进去.如果缓存区满了就把放进去的时间离现在最远的物品拿出来.问10^100次后每个物品在缓冲区中的概率

思路

如果是正着考虑,那么我们会出现很多废弃的状态。而且还会出现进去的被弹出来的情况,十分不好想。那么我们倒着考虑,那么最后一次加入的一定在最终的集合中。因为10^100基本上接近无限了,那么最后的集合一定是满的。

也就是一定存在k个不同的物品。

dp[i]表示到达状态i的概率。

dp[i|(1<<j)]+=dp[i]p[j] d p [ i | ( 1 << j ) ] + = d p [ i ] ∗ p [ j ] ,j不在i中。注意的是每次选择还有一定的概率选择到i集合中的数。所以dp[i]/=(1-sum) ,sum表示i集合中数的概率。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值