@ljt12138
2017-05-01T14:34:58.000000Z
字数 17151
阅读 1134
2-SAT裸题:
#include <bits/stdc++.h>using namespace std;const int MAXN = 505, MAXM = 10005;struct node {int to, next;} edge[MAXM];int head[MAXN], top = 0;void push(int i, int j){ edge[++top] = (node){j, head[i]}, head[i] = top; }int n, m;int neg(int nd){ return nd>n?nd-n:nd+n; }int T;int dfn[MAXN], low[MAXN], stk[MAXN], instk[MAXN], stop = 0, dftop = 0;bool tarjan(int nd){dfn[nd] = low[nd] = ++dftop;instk[nd] = 1, stk[++stop] = nd;for (int i = head[nd]; i; i = edge[i].next) {int to = edge[i].to;if (!dfn[to]) {if (!tarjan(to)) return 0;low[nd] = min(low[nd], low[to]);}else if (instk[to]) low[nd] = min(low[nd], dfn[to]);}if (dfn[nd] == low[nd]) {int now = 0;do {now = stk[stop--], instk[now] = 0;if (now == neg(nd)) return 0;} while (now != nd);}return 1;}bool fail(){memset(dfn, 0, sizeof dfn);for (int i = 1; i <= n*2; i++)if (!dfn[i])if (!tarjan(i)) return 1;return 0;}int main(){scanf("%d", &T);while (T--) {top = 0, memset(head, 0, sizeof head);dftop = 0, stop = 0;memset(instk, 0, sizeof instk);scanf("%d%d", &n, &m);for (int i = 1; i <= m; i++) {char t1, t2; int n1, n2;scanf("\n%c%d %c%d", &t1, &n1, &t2, &n2);if (t1 == 'm') n1 = neg(n1);if (t2 == 'm') n2 = neg(n2);push(neg(n1), n2), push(neg(n2), n1);}if (fail()) puts("BAD");else puts("GOOD");}return 0;}
网络流。http://hzwer.com/5992.html
#include <bits/stdc++.h>using namespace std;const int MAXN = 50*51, MAXM = 50*50*50;struct node {int to, next;long long flow;int neg;} edge[MAXM];int head[MAXN], top = 0;void push(int i, int j, long long f){++top, edge[top] = (node){j, head[i], f, top+1}, head[i] = top;++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;}int S = 2531, T = 2532;long long inf = 233333333333ll;int vis[MAXN], bfstime = 0, lev[MAXN];queue<int> que;bool bfs(){vis[S] = ++bfstime, lev[S] = 0, que.push(S);while (!que.empty()) {int f = que.front(); que.pop();for (int i = head[f]; i; i = edge[i].next) {int to = edge[i].to;long long fl = edge[i].flow;if (!fl || vis[to] == bfstime) continue;lev[to] = lev[f] + 1, vis[to] = bfstime, que.push(to);}}return vis[T] == bfstime;}long long dfs(int nd, long long mf = inf){if (nd == T || !mf) return mf;long long t, ans = 0;for (int i = head[nd]; i; i = edge[i].next) {int to = edge[i].to; long long f = edge[i].flow;if (!f || lev[to] != lev[nd]+1) continue;t = dfs(to, min(mf, f));ans += t, mf -= t;edge[i].flow -= t, edge[edge[i].neg].flow += t;}if (mf) lev[nd] = -1;return ans;}long long dinic(){long long ans = 0;while (bfs()) ans += dfs(S);return ans;}long long chess_board[55][55];int n, m, Tp;long long x[2] = {0,0}, sx[2] = {0,0};inline int number(int i, int j){ return (i-1)*m+j;}int dx[] = {0,1,0,-1}, dy[] = {1,0,-1,0};bool judge(long long z){bfstime = 0, top = 0, memset(head, 0, sizeof head);for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {if (z-chess_board[i][j] < 0) return 0;if ((i+j)&1) push(S, number(i, j), z-chess_board[i][j]);else push(number(i, j), T, z-chess_board[i][j]);}for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {if (!((i+j)&1)) continue;for (int k = 0; k < 4; k++) {int nx = i+dx[k], ny = j+dy[k];if (nx >= 1 && nx <= n && ny >= 1 && ny <= m)push(number(i, j), number(nx, ny), inf);}}long long fl = dinic();return fl == z*x[0]-sx[0];}int main(){scanf("%d", &Tp);while (Tp--) {scanf("%d%d", &n, &m);x[0] = x[1] = sx[0] = sx[1] = 0;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {scanf("%lld", &chess_board[i][j]);x[(i+j)&1]++, sx[(i+j)&1] += chess_board[i][j];}if (x[0] != x[1]) {if ((sx[0]-sx[1])%(x[0]-x[1]) != 0) puts("-1");else {long long val = (sx[0]-sx[1])/(x[0]-x[1]);if (judge(val)) printf("%lld\n", val*x[0]-sx[0]);else puts("-1");}} else {if (sx[0] != sx[1]) puts("-1");else {long long l = 0, r = inf, mid;while (l <= r) {mid = (l+r)>>1;if (!judge(mid)) l = mid+1;else r = mid-1;}printf("%lld\n", l*x[0]-sx[0]);}}}return 0;}
第一反应是可并堆.
然而可并堆的空间会不会爆炸呢..后来发现是不会炸的..每个元素至多只入一次堆,删除一次,总复杂度还是
结果写了可持久化权值线段树..离散化,找出dfn序用可持久化线段树维护区间内有值的点数和总和,然后二分就好,复杂度也是
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005, lgn = 20;int lc[MAXN*20], rc[MAXN*20], l[MAXN*20];int r[MAXN*20], top = 0;long long dat[MAXN*20], sum[MAXN*20], siz[MAXN*20], dx[MAXN];int root[MAXN];int n;long long m;inline void update(int nd){sum[nd] = sum[lc[nd]] + sum[rc[nd]] + dat[nd];if (l[nd] == r[nd]) siz[nd] = dat[nd] != 0;else siz[nd] = siz[lc[nd]] + siz[rc[nd]];}void build(int &nd, int opl, int opr){nd = ++top, l[nd] = opl, r[nd] = opr;if (opl < opr)build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);}void push(int prev, int &nd, int pos){nd = ++top, l[nd] = l[prev], r[nd] = r[prev];if (l[prev] == r[prev]) dat[nd] = dx[pos]/(n+1), update(nd);else {int mid = (l[prev]+r[prev])/2;if (pos <= mid) push(lc[prev], lc[nd], pos), rc[nd] = rc[prev], update(nd);else push(rc[prev], rc[nd], pos), lc[nd] = lc[prev], update(nd);}}int answer(int lpos, int rpos, long long sm){lpos--;int i = 1, j = n, mid, lr = root[lpos], rr = root[rpos];int ans = 0;while (i < j) {mid = (i+j)>>1;int lp = lc[lr], rp = lc[rr];if (sum[rp]-sum[lp] >= sm) lr = lp, rr = rp, j = mid;else sm -= sum[rp]-sum[lp], ans += siz[rp]-siz[lp], lr = rc[lr], rr = rc[rr], i = mid+1;}if (sm >= sum[rr]-sum[lr]) ans += siz[rr]-siz[lr];return ans;}struct node {int to, next;} edge[MAXN];int head[MAXN], tp = 0;void push(int i, int j){ edge[++tp] = (node){j, head[i]}, head[i] = tp; }int fa[MAXN], in[MAXN], out[MAXN], dfn = 0;long long money[MAXN], leader[MAXN];int dx_num(long long num, int i){ return lower_bound(dx+1, dx+n+1, num*(n+1)+i)-dx; }void dx_init(){for (int i = 1; i <= n; i++) dx[i] = money[i]*(n+1)+i;sort(dx+1, dx+n+1);}void dfs(int nd){in[nd] = ++dfn;push(root[dfn-1], root[dfn], dx_num(money[nd], nd));for (int i = head[nd]; i; i = edge[i].next)dfs(edge[i].to);out[nd] = dfn;}long long query(int nd){ return leader[nd]*answer(in[nd], out[nd], m); }int main(){scanf("%d%lld", &n, &m);int master = 0;for (int i = 1; i <= n; i++)scanf("%d%lld%lld", &fa[i], &money[i], &leader[i]);build(root[0], 1, n);dx_init();for (int i = 1; i <= n; i++) {if (!fa[i]) master = i;else push(fa[i], i);}dfs(master);long long ans = 0;for (int i = 1; i <= n; i++)ans = max(ans, query(i));printf("%lld\n", ans);return 0;}
没过...
用国内数据和hzwer及几分其他std拍都拍过了,然而bzoj上还是WA...奇特的是我们拿那份Te数据都WA一个点且结果一样。
然而hzwer代码bzoj可过而这份不可过...
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 100005, MAXM = 300105;int fa[MAXN];inline int findf(int nd){ return fa[nd]?fa[nd]=findf(fa[nd]):nd; }int gp[MAXN];long long siz[MAXN];inline int findgp(int nd){ return gp[nd]?gp[nd]=findgp(gp[nd]):nd; }void link(int i, int j){int a = findgp(i), b = findgp(j);if (a != b)gp[a] = b, siz[b] += siz[a];}struct edge {int x, y;long long c;int on_eg;edge(){ on_eg = 1; }friend bool operator < (const edge &a, const edge &b){ return a.c < b.c; }} edge[MAXM], knew[105], inp[MAXM];int n, m, k;const long long INF = 1234567891011ll;struct node {int to, next;long long dis;} graph[105];int head[MAXN], top = 0;int stk[50], t = 0;inline void push(int i, int j, long long dis){ //printf("%d--%lld-->%d\n", i, dis, j);graph[++top] = (node){j, head[i], dis}, head[i] = top; }void mst(int eg, int flag = 0, int p = 0){// cout << eg << endl;sort(edge+1, edge+eg+1);if (!p) memset(fa, 0, sizeof fa);else {for (int i = 1; i <= t; i++)fa[stk[i]] = 0;}for (int i = 1; i <= eg; i++) {int a = findf(findgp(edge[i].x)), b = findf(findgp(edge[i].y));if (a != b) {fa[a] = b;// printf("On MST --- %d, %d, %lld\n", a, b, edge[i].c);if (flag) {push(findgp(edge[i].x), findgp(edge[i].y), edge[i].c);push(findgp(edge[i].y), findgp(edge[i].x), edge[i].c);}} else {if (!p)edge[i].c = INF;edge[i].on_eg = 0;}}}void cut1(){memcpy(edge, inp, sizeof inp);int tp = m;for (int i = 1; i <= k; i++)edge[++tp] = knew[i], edge[tp].c = -INF;mst(tp);for (int i = 1; i <= tp; i++)if (abs(edge[i].c) != INF)link(edge[i].x, edge[i].y);}void cut2(){memcpy(edge, inp, sizeof inp);mst(m);int tp = m;m = 0;for (int i = 1; i <= tp; i++)if (edge[i].c != INF) {inp[++m] = edge[i], inp[m].on_eg = 1;// printf("Cut2 %d--%lld--%d\n", edge[i].x, edge[i].c, edge[i].y);}}int depth[MAXN], par[MAXN];long long peo[MAXN];long long lim[MAXN];void dfs(int nd, int f){depth[nd] = depth[f]+1;par[nd] = f, lim[nd] = INF;peo[nd] = siz[nd];for (int i = head[nd]; i; i = graph[i].next) {int to = graph[i].to;if (to != f) dfs(to, nd), peo[nd] += peo[to];}}void push_lim(int x, int y, long long l){while (x != y) {if (depth[x] >= depth[y]) {lim[x] = min(lim[x], l);x = par[x];} else {lim[y] = min(lim[y], l);y = par[y];}}}long long deal(int S){memcpy(edge, inp, k*16*sizeof(int));top = 0;int tp = m;// cout << "---" <<edge[1].c << endl;for (int i = 1; i <= t; i++)head[stk[i]] = 0;for (int i = 1; i <= k; i++)if (S&(1<<(i-1))) {edge[++tp] = knew[i], edge[tp].c = -INF, edge[tp].on_eg = 1;if (findgp(knew[i].x) == findgp(knew[i].y)) return 0ll;}// for (int i = 1; i <= tp; i++)// if (edge[i].on_eg != 1)// throw;mst(tp, 1, 1);// printf(" tp = %d \n", tp);dfs(findgp(1), 0);long long ans = 0;for (int i = 1; i <= tp; i++) {int x = findgp(edge[i].x), y = findgp(edge[i].y);if (edge[i].on_eg == 0) {push_lim(x, y, edge[i].c);// printf("Pushlim %d,%d -- %lld\n", x, y, edge[i].c);// edge[i].on_eg = 1;} //else printf("Lk %d -- %lld -- %d\n", x, edge[i].c, y);}for (int i = 1; i <= k; i++)if (S&(1<<(i-1))) {int x = findgp(knew[i].x), y = findgp(knew[i].y);if (depth[x] < depth[y]) swap(x, y);long long l = lim[x];ans += l*peo[x];// cout << x << " " << y << " " << l << " " << peo[x] << endl;}// cout << ans << endl;return ans;}int main(){freopen("toll.in", "r", stdin);freopen("toll.out", "w", stdout);scanf("%d%d%d", &n, &m, &k);for (int i = 1; i <= m; i++)scanf("%d%d%lld", &inp[i].x, &inp[i].y, &inp[i].c), inp[i].on_eg = 1;for (int i = 1; i <= k; i++)scanf("%d%d", &knew[i].x, &knew[i].y);for (int i = 1; i <= n; i++)scanf("%lld", &siz[i]);cut1();cut2();for (int i = 1; i <= n; i++)if (gp[i] == 0)stk[++t] = i;long long ans = 0;for (int i = 0; i < (1<<k); i++) {ans = max(ans, deal(i));}cout << ans << endl;return 0;}
第一反应是先找最长链,然后缩成一个点再找最长链,然而只有55分。
后来反应过来两个链相交会有损耗,于是看到了大爷题解中把环上边权设为-1再走最长链的方法..
APIO神题好多..知识水平不超过NOIP但是思维难度很大..
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;struct node {int to, next, dis, neg;} edge[MAXN*2];int head[MAXN], top = 0;void push(int i, int j){top++, edge[top] = (node){j, head[i], 1, top+1}, head[i] = top;top++, edge[top] = (node){i, head[j], 1, top-1}, head[j] = top;}int n, K;int gp[MAXN], siz[MAXN];int stk[MAXN], stop = 0;int ans = 0;int depth[MAXN], maxl[MAXN], secl[MAXN], maxps[MAXN], secps[MAXN];int fa[MAXN];void dfs(int nd, int f = 0){maxl[nd] = secl[nd] = maxps[nd] = secps[nd] = 0;for (int i = head[nd]; i; i = edge[i].next) {int to = edge[i].to;if (to == f) continue;fa[to] = i;depth[to] = depth[nd]+1, dfs(to, nd);if (maxl[to]+edge[i].dis >= maxl[nd]) secl[nd] = maxl[nd], secps[nd] = maxps[nd], maxl[nd] = maxl[to]+edge[i].dis, maxps[nd] = to;else if (maxl[to]+edge[i].dis > secl[nd]) secl[nd] = maxl[to]+edge[i].dis, secps[nd] = to;}}void deal(){memset(depth, 0, sizeof depth);dfs(1, 0);//puts("---");int len = 0, nd;for (int i = 1; i <= n; i++)if (maxl[i] + secl[i] > len) len = maxl[i]+secl[i], nd = i;//puts("---");ans -= len*2, ans += len+1;for (int i = maxps[nd]; i; i = maxps[i])edge[fa[i]].dis = -1, edge[edge[fa[i]].neg].dis = -1;for (int i = secps[nd]; i; i = maxps[i])edge[fa[i]].dis = -1, edge[edge[fa[i]].neg].dis = -1;//puts("---");}int main(){scanf("%d%d", &n, &K);memset(gp, 0, sizeof gp);for (int i = 1; i <= n; i++) siz[i] = 1;for (int i = 1; i < n; i++) {int u, v; scanf("%d%d", &u, &v);push(u, v);}ans = (n-1)*2;deal();if (K == 2) deal();cout << ans << endl;return 0;}
学习一个期望dp..
设
#include <bits/stdc++.h>using namespace std;double dp[105][(1<<16)+1];int k, n;int rp[105], st[105];int main(){scanf("%d%d", &k, &n);for (int i = 1; i <= n; i++) {int t, u;scanf("%d", &rp[i]);st[i] = 0;while (scanf("%d", &u), u != 0)st[i] |= (1<<(u-1));}for (int i = 0; i < (1<<n); i++) dp[k+1][i] = 0;for (int i = k; i >= 1; i--) {for (int j = 0; j < (1<<n); j++) {dp[i][j] = 0;for (int p = 1; p <= n; p++) {if ((j&st[p])==st[p])dp[i][j] += max(dp[i+1][j], dp[i+1][j|(1<<(p-1))]+rp[p]*1.0);elsedp[i][j] += dp[i+1][j];}dp[i][j] /= n;}}printf("%.6f\n", dp[1][0]);return 0;}
分别计算贡献,令
#include <bits/stdc++.h>using namespace std;int n, A, B, C;int a[10000005];int main(){scanf("%d%d%d%d%d", &n, &A, &B, &C, a+1);for (int i=2;i<=n;i++) a[i] = ((long long)a[i-1] * A + B) % 100000001;for (int i=1;i<=n;i++) a[i] = a[i] % C + 1;// for (int i = 1; i <= n; i++) cout << a[i] << " "; puts("");double now = 0;a[0] = a[n];for (int i = 1; i <= n; i++) {now = min(a[i],a[i-1])*1.0/a[i]/a[i-1]+now;}printf("%.3f\n", now);return 0;}
大力递推可以
#include <bits/stdc++.h>using namespace std;double p[100005];int n;double dp[100005];int main(){scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);for (int i = 1; i <= n; i++) {dp[i] = 0;for (int k = 0; k <= i; k++) {if (k+1 <= i) {double tmp = 1-p[k];for (int j = k+1; j <= i; j++)tmp *= p[j];dp[i] += tmp*((i-k)*(i-k)*(i-k)+dp[k-1]);} else dp[i] += dp[k-1]*(1-p[k]);}}cout << dp[n] << endl;return 0;}
然而这个做法没有很好地利用期望的线性性质,即
注意:
#include <bits/stdc++.h>using namespace std;double p[100005];int n;int main(){scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);double x, x2, ans; x = x2 = 0, ans = 0;for (int i = 1; i <= n; i++) {ans += (x2*3+3*x+1)*p[i];x2 = (x2+2*x+1)*p[i];x = (x+1)*p[i];}printf("%.1f\n", ans);return 0;}
例如有
令
f[to] += f[nd]/d[tp];dp[to] += dp[nd]/cd[tp]+c(nd,to)*f[nd]/cd[nd];
#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;struct node {int to, next, dis;} edge[MAXN*2];int head[MAXN], top = 0, rd[MAXN], cd[MAXN];void push(int i, int j, int d){ edge[++top] = (node){j, head[i], d}, head[i] = top, rd[j]++, cd[i]++; }int stk[MAXN], stop = 0;int n, m;double dp[MAXN], f[MAXN];int main(){scanf("%d%d", &n, &m);for (int i = 1; i <= m; i++) {int u, v, d;scanf("%d%d%d", &u, &v, &d);push(u, v, d);}stk[++stop] = 1;dp[1] = 0, f[1] = 1;while (stop) {int tp = stk[stop--];for (int i = head[tp]; i; i = edge[i].next) {int to = edge[i].to;f[to] += f[tp]/cd[tp], dp[to] += dp[tp]/cd[tp]+edge[i].dis*f[tp]/cd[tp];rd[to]--;if (rd[to] == 0) stk[++stop] = to;}}printf("%.2f\n", dp[n]);return 0;}
终于来填坑了...
考场上设计的状态
正确的思路应该是
#include <bits/stdc++.h>using namespace std;int n, m, v, e;int g[505][505];int c[2005][2];double k[2005];double f[2005][2005][2];int main(){scanf("%d%d%d%d", &n, &m, &v, &e);for (int i = 1; i <= n; i++) scanf("%d", &c[i][0]);for (int i = 1; i <= n; i++) scanf("%d", &c[i][1]);for (int i = 1; i <= n; i++) scanf("%lf", &k[i]);memset(g, 127/3, sizeof g);for (int i = 1; i <= v; i++) g[i][i] = 0;for (int i = 1; i <= e; i++) {int u, v, d; scanf("%d%d%d", &u, &v, &d);g[u][v] = g[v][u] = min(g[u][v], d);}for (int k = 1; k <= v; k++)for (int i = 1; i <= v; i++)for (int j = 1; j <= v; j++)g[j][i] = g[i][j] = min(g[i][j], g[i][k]+g[k][j]);for (int i = 0; i <= m; i++) f[1][i][0] = f[1][i][1] = 1e10;f[1][0][0] = f[1][1][1] = f[1][1][0] = 0;for (int i = 2; i <= n; i++) {for (register int j = 0; j <= m; j++) {f[i][j][0] = f[i][j][1] = 1e10;f[i][j][0] = min(f[i-1][j][0]+g[c[i-1][0]][c[i][0]],f[i-1][j][1]+k[i-1]*g[c[i-1][1]][c[i][0]]+(1-k[i-1])*g[c[i-1][0]][c[i][0]]);if (j != 0) {f[i][j][1] = min(f[i-1][j-1][0]+k[i]*g[c[i-1][0]][c[i][1]]+(1-k[i])*g[c[i-1][0]][c[i][0]],f[i-1][j-1][1]+k[i]*k[i-1]*g[c[i-1][1]][c[i][1]]+(1-k[i-1])*(1-k[i])*g[c[i-1][0]][c[i][0]]+k[i]*(1-k[i-1])*g[c[i-1][0]][c[i][1]]+k[i-1]*(1-k[i])*g[c[i-1][1]][c[i][0]]);f[i][j][0] = min(f[i][j][0], f[i][j-1][0]);f[i][j][1] = min(f[i][j][1], f[i][j-1][1]);}}}double ans = f[n][0][0];for (int i = 1; i <= m; i++) ans = min(f[n][i][1], f[n][i][0]);printf("%.2f\n", ans);return 0;}
huzecong dalao的神题...
直接dp会发现无论怎么设计状态都不可能消除后效性。
然后就比较神了,分别计算每个卡牌的贡献,如果我们知道了这个卡牌
也就是至少发动一次的概率(即一次也不发动的反面)。而在哪一次发动则对于这个卡牌的贡献是等价的,我们已经通过计算
#include <bits/stdc++.h>using namespace std;int T, n, r;double dp[225][140];double p[225], d[225];int main(){scanf("%d", &T);while (T--) {scanf("%d%d", &n, &r);double tmp = 1;for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i], &d[i]), tmp *= p[i];double ans = 0;memset(dp, 0, sizeof dp);dp[0][r] = 1;for (int i = 1; i <= n; i++)for (int j = 0; j <= r; j++) {dp[i][j] = dp[i-1][j]*pow(1-p[i-1], j)+dp[i-1][j+1]*(1-pow(1-p[i-1], j+1));ans += dp[i][j]*(1-pow(1-p[i], j))*d[i];}printf("%.10f\n", ans);}return 0;}
和《游走》那个题套路一样。
把一个有序对看成状态列转移矩阵
然后就完了。
脑残的我把
#include <bits/stdc++.h>using namespace std;double A[405][805];int g[25][25], n, m, u, v, a, b;double p[25], eps = 1e-10;inline int num(int i, int j){ return (i-1)*n+j; }void inverse(){for (int i = 1; i <= n*n; i++) A[i][i+n*n] = 1;for (int i = 1; i <= n*n; i++) {int k = i;while (abs(A[k][i]) <= eps) k++;swap(A[i], A[k]);for (int j = 1; j <= n*n; j++) {if (j == i) continue;double tmp = -A[j][i]/A[i][i];for (int k = 1; k <= 2*n*n; k++)A[j][k] += A[i][k]*tmp;//, printf("%f ",A[j][k]);}}for (int i = 1; i <= n*n; i++)for (int j = n*n+1; j <= n*n*2; j++)A[i][j] /= A[i][i];for (int i = 1; i <= n*n; i++)for (int j = 1; j <= n*n; j++)A[i][j] = A[i][j+n*n];}int main(){scanf("%d%d%d%d", &n, &m, &a, &b);for (int i = 1; i <= m; i++)scanf("%d%d", &u, &v), g[u][v] = g[v][u] = 1, g[v][v]++, g[u][u]++;for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)for (int k = 1; k <= n; k++)for (int l = 1; l <= n; l++) { // (i,j)-->(k,l)if ((i == k || g[i][k]) && (g[j][l] || j==l)) {double ti = i==k?p[i]:(1-p[i])*1.0/g[i][i];double tj = j==l?p[j]:(1-p[j])*1.0/g[j][j];A[num(k,l)][num(i,j)] = -ti*tj;}if (i == j)A[num(k,l)][num(i,j)] = 0;}for (int i = 1; i <= n*n; i++) A[i][i] += 1;inverse();for (int i = 1; i <= n; i++)printf("%.6f ", A[num(i,i)][num(a,b)]);return 0;}