bzoj2337 [HNOI2011]XOR和路径

题目链接

solution

首先想对于每个二进制位分别计算。

\(f[i]\)表示第\(i\)个点走到\(n\)异或和为\(1\)的概率。用\(du[i]\)表示第\(i\)个点的度数,那么就有

\[f[u]=\frac{1}{du[u]}(\sum\limits_{w(u,v)=1}(1-f[v])+\sum\limits_{w(u,v)=0}f[v])\\ \Rightarrow du[u]f[u]=\sum\limits_{w(u,v)=1}1-\sum\limits_{w(u,v)=1}f[v]+\sum\limits_{w(u,v)=0}f[v]\\ \Rightarrow \sum\limits_{w(u,v)=1}1=du[u]f[u]+\sum\limits_{w(u,v)=1}f[v]-\sum\limits_{w(u,v)=0}f[v] \]

然后高斯消元就行了。

对于第\(x\)位的答案就是\(2^x\times a[1][1]\)

code

/*
* @Author: wxyww
* @Date:   2020-04-27 18:46:32
* @Last Modified time: 2020-04-27 19:31:34
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 110;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
struct node {
	int v,nxt,w;
}e[N * N * 2];
int du[N],head[N],ejs;
void add(int u,int v,int w) {
	e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
int n,m;
double a[N][N];
void pre(int x) {
	x = (1 << x);
	a[n][n] = 1;//f[n] = 1!!!
	memset(a,0,sizeof(a));
	for(int u = 1;u < n;++u) {//u < n !!!!
		a[u][u] = du[u];
		for(int i = head[u];i;i = e[i].nxt) {
			int v = e[i].v;
			if(e[i].w & x) a[u][v]++,a[u][n + 1]++;
			else a[u][v]--;
		}
	}
}
void Guass() {
	for(int i = 1;i <= n;++i) {
		int t = i;
		for(int j = i + 1;j <= n;++j)
			if(a[j][i] > a[t][i]) t = j;

		if(fabs(a[t][i]) < 1e-8) continue;

		swap(a[i],a[t]);

		for(int j = 1;j <= n;++j) {
			if(j == i) continue;
			double tmp = a[j][i] / a[i][i];
			for(int k = 1;k <= n + 1;++k) 
				a[j][k] -= a[i][k] * tmp;
		}

	}
}
int main() {
	n = read(),m = read();
	for(int i = 1;i <= m;++i) {
		int u = read(),v = read(),w = read();
		add(u,v,w);
		du[u]++;
		if(u != v) 
			du[v]++,add(v,u,w);
	}
	double ans = 0;
	for(int i = 30;i >= 0;--i) {
		pre(i);
		Guass();

		ans += (a[1][n + 1] / a[1][1]) * (1 << i);
	}
	printf("%.3lf\n",ans);

	return 0;
}

/*
3 3
1 2 4
1 3 5
*/

猜你喜欢

转载自www.cnblogs.com/wxyww/p/bzoj2337.html