zoukankan      html  css  js  c++  java
  • 期望DP

    整理一些期望dp的题目,会不断更新

    BZOJ4318 OSU!

    题意

    (;)
    现在你有一个长度为(n)的字符串,对于第i位来说,有(a(i))的概率是1,现在定义你获得分数为每一段极长连续的1的长度的立方和。
    例如:00100010的分数即为(2^3+3^3+1^3=36)
    数据范围:(nleq 10^5)
    (;)

    Solution

    (;)
    我们用(f_0(i))表示以i为结尾的连续的一段1的长度的期望
    那么第i位有(a(i))的概率是1,则对于这种情况的长度,即为(f_0(i-1)+1)
    否则说明是0,那么长度一定为0
    所以(f_0(i)=a(i) imes (f_0(i-1)+1))
    (;)
    然后我们用(f_1(i))表示以i为结尾的连续的一段1的长度平方的期望
    根据刚才的转移方程,我们可以得到:
    (E[f_1(i)]=E[f_0(i)^2]=E[a(i) imes (f_0(i-1)+1)^2]=E[a(i) imes (f_1(i-1)+2f_0(i-1)+1)]=a(i) imes (E[f_1(i-1)]+2E[f_0(i-1)]+1))
    同理(f_2(i))表示以i为结尾的连续的一段1的长度的立方的期望,即:
    (E[f_2(i)]=E[f_0(i)^3]=E[a(i) imes (f_0(i-1)+1)^3]=a(i) imes E[f_2(i-1)+3f_1(i-1)+3f_0(i-1)+1]=a(i) imes (E[f_2(i-1)]+3E[f_1(i-1)]+3E[f_0(i-1)]+1))
    那么统计答案的时候考虑以每一位为结尾的一段1,则需要满足(i+1)位为0,即:((1-a_{i+1}) imes f_2(i))
    时间复杂度:(O(n))
    (;)

    BZOJ3143 游走

    题意

    (;)
    现在你有一个(n)个点(m)条边的无向连通图,从1号点出发,每一步会等概率地选择当前点连出去地某条边进行游走,到(n)号点停止。
    现在你要为这(m)条边分配编号,定义一条边的长度为这条边的编号,求从1号点到(n)号点经过长度的最小期望
    数据范围:(nleq 500 ;;m leq 125000)
    (;)

    Solution

    (;)

    Step 1

    (;)
    如何分配边的id?
    首先我们有一个贪心的思路:因为我们从1号点到(n)号点的这条路径上的每条边可能会经过多次
    所以我们要使经过次数的多的边的id尽可能地小,使经过次数少的边的id尽可能的大
    所以问题就被转化为了如何求经过一条边的次数的期望
    (;)

    Step 2

    (;)
    而对于((u,v))这条边,由于是无向的,所以有可能是(u->v)(v->u)
    所以(E[edge(u,v)]=frac{1}{deg[u]} imes E[u] +frac{1}{deg[v]} imes E[v])
    所以问题进而转化为如何求经过一个点的次数的期望
    (;)

    Step 3

    (;)
    那么问题到这里就变得简单了
    本质与绿豆蛙的归宿这道题一样,dp转移方程即为:
    (E[v]=sum_{in edge(u,v)}frac{1}{deg[u]} imes E[u])
    而这个东西是又后效性的,我们无法直接递推的求
    所以我们把刚刚那个柿子移项,写成如下形式:
    (a_1E[1]+a_2E[2]+cdots+a_nE[n]=a_{n+1})
    那么对于这(n)个点来说,就能写出(n)个这样的方程。
    所以,直接高斯消元求解。
    (;)

    Step 4

    (;)
    如何统计答案?
    首先我们将边按(E[])从小到大排序,这样我们也能把每一条边的(id)给确定下来
    然后我们对于每条边分别考虑贡献,那么(edge(u,v))这条边的贡献显然为(id imes E[edge(u,v)])
    时间复杂度:(O(n^3+mlog(m)))
    (;)

    Code

    #include <bits/stdc++.h>
    const int N = 510, M = 200010;
    int n, m, d[N][N], deg[N];
    double dp[N], g[N][N], res[N], f[M];
    struct Edge
    {
    	int from, to;
    }e[M];
    void gauss()
    {
    	for(int i=1;i<n;i++)
    	{
    		for(int j=i+1;j<n;j++)
    		{
    			if(fabs(g[j][i]) > fabs(g[i][i]))
    			{
    				for(int k=1;k<=n+1;k++)
    				{
    					std::swap(g[i][k], g[j][k]);
    				}
    			}
    		}
    		if(fabs(g[i][i]) <= 1e-8) continue;
    		for(int j=i+1;j<n;j++)
    		{
    			double tmp = g[j][i] / g[i][i];
    			for(int k=1;k<=n+1;k++) 
    			{
    				g[j][k] = g[j][k] - tmp * g[i][k];
    			}
    		}
    	}
    }
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i=1;i<=m;i++)
    	{
    		int u, v;
    		scanf("%d%d", &u, &v);
    		d[u][v] = d[v][u] = 1; deg[u] ++; deg[v] ++;
    		e[i].from = u; e[i].to = v;
    	}
    	for(int i=1;i<n;i++)
    	{
    		g[i][i] = -1.0;
    		for(int j=1;j<n;j++)
    		{
    			if(d[i][j]) 
    			{
    				g[i][j] = (double) 1 / deg[j];
    			}
    		} 
    		if(i == 1) g[i][n + 1] = -1.0;
    	}
    	gauss();
    	for(int i=n-1;i>=1;i--)
    	{
    		double now = 0.0;
    		for(int j=i+1;j<n;j++) now = now + g[i][j] * res[j];
    		res[i] = (g[i][n + 1] - now) / g[i][i];
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int u = e[i].from, v = e[i].to;
    		if(u != n) f[i] += res[u] / deg[u];
    		if(v != n) f[i] += res[v] / deg[v];
    	}
    	std::sort(f + 1, f + m + 1);
    	double ans = 0;
    	for(int i=1;i<=m;i++)
    	{
    		ans += f[i] * (m - i + 1);
    	}
    	printf("%.3lf", ans);
    	return 0;
    } 
    
  • 相关阅读:
    BZOJ3689: 异或之
    BZOJ3166: [Heoi2013]Alo
    BZOJ3261: 最大异或和
    BZOJ3123: [Sdoi2013]森林
    BZOJ4520: [Cqoi2016]K远点对
    BZOJ2989: 数列
    BZOJ1941: [Sdoi2010]Hide and Seek
    BZOJ4066: 简单题
    BZOJ2648: SJY摆棋子
    KDtree模板(HDU4347)
  • 原文地址:https://www.cnblogs.com/czyty114/p/13762504.html
Copyright © 2011-2022 走看看