ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

简单期望DP

2021-02-16 18:03:09  阅读:137  来源: 互联网

标签:const int double ans db 简单 期望 include DP


关键性质:

\[\begin{align} & E(C)=E(C) \tag{1} \\ & E(CX)=CE(x) \tag{2}\\ & E(x+y)=E(x)+E(y) \tag{3}\\ & x\cap y=\emptyset \Rightarrow E(xy)=E(x)E(y) \tag{4} \end{align} \]

PS:
\((3)\)特别重要,很多题通过递推解决
\((4)\)可以解决独立随机变量之积的情况

例题

Luogu P4316 绿豆蛙的归宿

题链
正向做比较麻烦,设\(f[i]\)是\(1->i\)的期望,\(g[i]\)是\(1->i\)的概率
边权要乘g
可以反向做,设\(f[i]\)是\(i->n\)的期望,反向作一遍即可

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;
int cnt,to[N],nxt[N],he[N],w[N];
int n,m,d[N],deg[N],l,r,q[N];
double f[N];

inline void add(int u,int v,int k) {
	to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
	w[cnt]=k;
}

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) {
		int u,v,k; scanf("%d%d%d",&u,&v,&k);
		add(v,u,k);
		d[u]++,deg[u]++;
	}
	q[l=r=1]=n;
	while(l<=r) {
		int u=q[l]; l++;
		for(int e=he[u];e;e=nxt[e]) {
			int v=to[e];
			d[v]--;
			f[v]+=(f[u]+w[e])/deg[v];
			if(d[v]==0) q[++r]=v;
		}
	}
	printf("%.2lf\n",f[1]);
	return 0;
}

LuoguP1654 OSU!

题链

\[\begin{align} & a+1=a+1 \\ &(a+1)^2=a^2+2a+1 \\ & (a+1)^3=a^3+3a^2+3a+1 \\ \end{align} \]

依次维护\(a^3,a^2,a\)的期望即可

#include <bits/stdc++.h>
#define db double
using namespace std;

const int N = 3e5 + 5;
int n;
db f1, f2, ans, a[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lf", &a[i]);
    }
    for (int i = 1; i <= n; i++) {
        ans += (f2 * 3 + f1 * 3 + 1) * a[i];
        f2 = (f2 + f1 * 2 + 1) * a[i];
        f1 = (f1 + 1) * a[i];
    }
    printf("%.1lf\n", ans);
    return 0;
}

BZOJ2201 彩色圆环

考虑链上,DP显然
考虑环上,枚举头,再枚举尾和头颜色一样的数量\(j\),则\(n-j\)是链的情况且头和尾不同,不妨设\(f[i][0/1]\)表示前\(i\)个头和尾是否相同的期望答案
时间复杂度\(O(n^3)\),过了
写完发现\(f[i][0/1]\)都一样,所以\(O(n^2)\)解决

#include<bits/stdc++.h>
#define db double
using namespace std ;

const int N=205;
int n,m;
db p[N],ans,f[N][2];

int main() {
	scanf("%d%d",&n,&m);
	p[0]=1;
	for(int i=1;i<=n;i++) p[i]=p[i-1]/m;
	ans=p[n]*n*m;
	for(int k=1;k<n;k++) {
		for(int i=1;i<=n;i++) f[i][0]=f[i][1]=0;
		f[k][1]=1;
		for(int i=k+1;i<=n;i++) {
			for(int j=k;j<i;j++) {
				f[i][0]+=f[j][0]*p[i-j]*(i-j)*(m-2)+f[j][1]*p[i-j]*(i-j)*(m-1);
				f[i][1]+=f[j][0]*p[i-j]*(i-j);
			}
		}
		for(int i=k;i<=n;i++) {
			ans+=f[i][0]*(n-i+k)*p[n-i+k]*m;
		}	
	}
	printf("%.5lf\n",ans);
	return 0;
}

Luogu P3232 [HNOI2013]游走

题链
显然最优解是期望经过最大的边的权值最小
\(f[i]\)表示从\(i\)节点出去的期望数量
可以列出n-1个方程,其中\(f[n]=0\),\(f[1]\)要加\(1\),高斯消元
然后求出边的期望即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define db long double
const db eps=1e-6;
using namespace std;

const int N=1005,M=1e6+5;
int n,m,deg[N],u[M],v[M];
bool e[N][N];
db a[N][N],ans[N],E[M],s;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&u[i],&v[i]);
		e[u[i]][v[i]]=1;
		e[v[i]][u[i]]=1;
		deg[u[i]]++;
		deg[v[i]]++;
	}
	ans[n]=0;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=1;j<=n-1;j++)
			if(e[i][j]) a[i][j]=(db)1/deg[j];
		a[i][i]=-1;
	}
	a[1][n]=-1;
	for(int i=1;i<=n-1;i++)
	{
		if(abs(a[i][i])<=eps)
			for(int j=i+1;j<=n-1;j++)
				if(abs(a[j][i])>eps)
				{
					for(int k=i;k<=n;k++)
						swap(a[i][k],a[j][k]);
					break;
				}
		for(int j=i+1;j<=n-1;j++)
		if(abs(a[j][i])>eps)
		{
			db b=a[i][i]/a[j][i];
			a[j][i]=0;
			for(int k=i+1;k<=n;k++)
				a[j][k]=a[j][k]*b-a[i][k];
		}
	}
	for(int i=n-1;i>=1;i--)
	{
		ans[i]=a[i][n];
		for(int j=i+1;j<=n-1;j++)
			ans[i]-=a[i][j]*ans[j];
		ans[i]/=a[i][i];
	}
	for(int i=1;i<=m;i++)
		E[i]=ans[u[i]]/deg[u[i]]+ans[v[i]]/deg[v[i]];
	sort(E+1,E+m+1);
	s=0;
	for(int i=1;i<=m;i++)
		s+=E[i]*(m-i+1);
	printf("%.3Lf\n",s);
	return 0;
}

选书问题

注意:每个人选书是从小到大的
选每本书的概率可以用等比数列求和的方法求出
然后用树状数组维护期望

#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;
int n,m;
long double p,mi[N],c[N],ans;
vector<int>a[N];

inline long double ask(int x) {
	double ret=0;
	for(x;x<=n;x+=x&-x) ret+=c[x];
	return ret; 
}
inline void add(int x,long double k) {
	for(x;x;x-=x&-x) c[x]+=k;
}
int main() {
	scanf("%d%d%Lf",&n,&m,&p);
	mi[0]=1;
	for(int i=1;i<=n;i++) mi[i]=mi[i-1]*(1-p);
	for(int i=1;i<=m;i++) {
		int u,v; scanf("%d%d",&u,&v);
		a[u].push_back(v);
	}
	for(int i=1;i<=n;i++) {
		int num=a[i].size();
		sort(a[i].begin(),a[i].end());
		for(int j=0;j<num;j++) {
			ans+=p*mi[j]/(1-mi[num])*ask(a[i][j]+1);
		}
		for(int j=0;j<num;j++)  {
			add(a[i][j],p*mi[j]/(1-mi[num]));
		}
	}
	printf("%.2Lf\n",(long double)round(ans*100)/100);
	return 0;
}

Luogu P3750 [六省联考2017]分手是祝愿

题链
若灯状态已知,显然从大到小关最优
对于每个数枚举约数,\(O(n\sqrt n)\) ;但如果考虑对每个数枚举倍数,时间复杂度是调和级数 \(O(n lg n)\)
预处理出需要几步
\(f[i]\)表示需要\(i->\)需要\(i-1\)的期望步数

\[f[i]=\frac{i}{n}+(1-\frac{i}{n})f[i+1] \]

由于上限是\(n\)步,所以\(f[n]=1\)

#include<bits/stdc++.h>
#define ll long long 
const int p=1e5+3;
using namespace std;

const int N=1e5+5;
int n,m,a[N],ans,num,f[N],K,inv[N];
vector<int>v[N];
int main() {
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++) {
		for(int j=i+i;j<=n;j+=i) {
			v[j].push_back(i);
		}
	}
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
	}
	num=0;
	for(int i=n;i;i--) {
		if(a[i]) {
			num++;
			for(auto j:v[i]) {
				a[j]=1-a[j];
			}
		}
	}
	if(num<=K) {
		for(int i=1;i<=n;i++) num=(ll)num*i%p;
		printf("%d\n",num);
		return 0;
	}
	inv[1]=1;
	for(int i=2;i<=n;i++) inv[i]=(ll)(p-p/i)*inv[p%i]%p;
	f[n]=1;
	for(int i=n-1;i>K;i--) {
		f[i]=((ll)(n-i)*f[i+1]+n)*inv[i]%p;
	}
	for(int i=num;i>K;i--) ans=(ans+f[i])%p;
	ans+=K;
	for(int i=1;i<=n;i++) ans=(ll)ans*i%p;
	printf("%d\n",ans);
	return 0;
}

bzoj3029 守卫者的挑战

\(f[i][j][k]\)表示前\(i\)关,过了\(j\)关,背包容量为\(k\)的概率
发现\(n\)只有200,背包容量只需\([-200,200]\)即可
我为人人

#include<bits/stdc++.h>
using namespace std;

const int N=205;
int n,L,K,a[N];
double p[N],f[N][N][N+N];

int main() {
	scanf("%d%d%d",&n,&L,&K); K=min(K,n);
	for(int i=1;i<=n;i++) scanf("%lf",&p[i]),p[i]/=100;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	f[0][0][K+n]=1;
	for(int i=0;i<n;i++) {
		for(int j=0;j<=i;j++) {
			for(int k=1;k<=n+n;k++) {
				f[i+1][j][k]+=f[i][j][k]*(1-p[i+1]);
				f[i+1][j+1][min(k+a[i+1],n+n)]+=f[i][j][k]*p[i+1];
			}
		}
	}
	double ans=0;
	for(int i=L;i<=n;i++) {
		for(int j=n;j<=n+n;j++) {
			ans+=f[n][i][j];
		//	if(f[n][i][j]) printf("%d %d %.3lf\n",i,j,f[n][i][j]);
		}
	}
	printf("%.6lf\n",ans);
	return 0;
}

标签:const,int,double,ans,db,简单,期望,include,DP
来源: https://www.cnblogs.com/wsfwsf/p/14407067.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有