介于本校OJ,题面如下:
SOL
一、不存在一个点,满足从它出发能走回来,换而言之,此题为有向无环图 D A G DAG DAG,可能是拓扑排序然后dp,接下来思考dp。
二、思考状态定义,求异或和无法直接用期望转移。分析异或运算的特点,将两数拆分成二进制,按位 相同则0,不同则1,即每一位相互独立,互不影响,
v
i
≤
1
e
9
v_{i}\le1e9
vi≤1e9 ,最高不过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)
k(0/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;
}