NOIP模拟 闲荡【拓扑序+概率dp】

介于本校OJ,题面如下:
在这里插入图片描述

在这里插入图片描述


SOL

一、不存在一个点,满足从它出发能走回来,换而言之,此题为有向无环图 D A G DAG DAG,可能是拓扑排序然后dp,接下来思考dp。

二、思考状态定义,求异或和无法直接用期望转移。分析异或运算的特点,将两数拆分成二进制,按位 相同则0,不同则1,即每一位相互独立,互不影响, v i ≤ 1 e 9 v_{i}\le1e9 vi1e9 ,最高不过30位,可以按位计算概率。
则状态方程 : f [ k ] [ j ] [ i ] f[k][j][i] f[k][j][i] 表示 从 i i i点出发的运算值中,第 j j j位为 k ( 0 / 1 ) k(0/1) k0/1的概率

三、状态转移:
f [ n o w   x o r   n x t ] [ j ] [ u ] + = f [ n x t ] [ j ] [ v ] f[now\ xor\ nxt][j][u]+=f[nxt][j][v] f[now xor nxt][j][u]+=f[nxt][j][v]
n o w now now为当前 u u u j j j位的值, n x t nxt nxt为下一点 v v v j j j位的值;

//dp状态定义可以降维优化,这里不讨论了。

//本来切了这题,结果拓扑序写错了,调了好久。。。


CODE

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
#define cs const
inline int red()
{
    int data=0;int w=1; char ch=0;
    ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
#define in red()
cs int N=1e5+10;
vector <int> g[N],V;
int n,m,vl[N],ed[N];
bool st[N];
db f[2][35][N],ans[N];
inline void bfs(){
	for(int i=1;i<=n;++i){
		if(!ed[i])g[0].push_back(i),++ed[i];
		if(!st[i])g[i].push_back(n+1);	
	}
	V.push_back(0);
	int i=0,j=0;
	for(;i<=j;++i){
		int u=V[i];
		int up=g[u].size();
		for(int k=0;k<up;++k){
			--ed[g[u][k]];
			if(ed[g[u][k]]==0)V.push_back(g[u][k]),++j;
		}
	}
}
inline void solve(){
	for(int i=0;i<=30;++i)f[0][i][n+1]=1;
	int up=V.size();
	for(int p=up-1;p>=1;--p){
		int u=V[p],up=g[u].size();
		for(int i=0;i<up;++i){
			int v=g[u][i],val=vl[u];
			for(int j=0;j<=30;++j){
				bool now=val&1;
				for(int las=0;las<=1;++las){
					if(f[las][j][v]!=0.0){
						f[now^las][j][u]+=f[las][j][v]/(up*1.0);
					}
				}
				val>>=1;
			}
		}
		for(int j=0;j<=30;++j){
			ans[u]+=(1<<j)*f[1][j][u];
		}
	}
	for(int i=1;i<=n;++i)pf("%.3lf\n",ans[i]);
}
signed main(){
	n=in;m=in;
	for(int i=1;i<=n;++i)vl[i]=in;
	for(int i=1;i<=m;++i){
		int u=in,v=in;
		g[u].push_back(v);st[u]=1;++ed[v];
	}	
	bfs();
	solve();
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值