高斯消元,就是 $O(n^3)$ 解方程组
线性基,就是一组线性无关的数,用它们可以异或出原集合可以异或出的所有数,对于一组线性基 $\{a_1,a_2,...,a_n\}$ ,$a_i$ 的最高位 $1$ 在第 $i$ 位
拟阵啥的...不想学
bzoj3270 博物馆
一个无向图,两个人一个在 A 一个在 B,这两个人开始随机走,求这两个人在每个点相遇的概率(在边上不会相遇),每个点有一个自环,每次有 $P_i$ 的概率走自环,剩下 $1 - P_i$ 的概率等概率选一个相邻点走过去
$n \leq 20$
sol:
我是不是...开错题了?
原题等价于求这两个人在每个点相遇的期望步数
设 $f_{(i,j)}$ 为第一个人在 $i$ ,第二个人在 $j$ 的期望步数,枚举这两个人走的情况转移
注意:
1.$i==j$ 的点不转移,因为相遇了就停了
2.因为一开始就在起点,所以起点的概率要 $+1$ ,概率 $+1$ 相当于方程解出来右边是 $-1$
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 410; int n,m,A,B; int d[maxn];double pr[maxn],a[maxn][maxn]; vector<int> G[maxn]; int mem[25][25],dfn; inline int f(int x,int y){return mem[x][y] ? mem[x][y] : (mem[x][y] = ++dfn);} void gauss() { int now=1,tot = n * n; for(int i=1;i<=tot;i++) { int j; for(j=now;!a[j][now]&&j<=tot;j++); for(int k=1;k<=tot+1;k++)swap(a[now][k],a[j][k]); for(int j=1;j<=tot;j++) if(j!=now) { double t=a[j][now]/a[now][now]; for(int k=1;k<=tot+1;k++) a[j][k]-=t*a[now][k]; } now++; } } int main() { n = read(),m = read(),A = read(),B = read(); for(int i=1;i<=n;i++)G[i].push_back(i);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f(i,j); a[f(A,B)][n * n + 1] = -1; for(int i=1;i<=m;i++) { int u = read(),v = read(); d[u]++;G[u].push_back(v); d[v]++;G[v].push_back(u); } for(int i=1;i<=n;i++)cin >> pr[i]; for(int x=1;x<=n;x++) for(int y=1;y<=n;y++) { a[f(x,y)][f(x,y)]--; for(int i=0;i<G[x].size();i++) for(int j=0;j<G[y].size();j++) { int tx = G[x][i],ty = G[y][j]; int p = f(x,y),np = f(tx,ty); if(tx == ty)continue; if(tx == x && ty == y)a[p][np] += pr[x] * pr[y]; else if(tx == x && ty != y)a[p][np] += pr[x] * (1 - pr[ty]) / d[ty]; else if(tx != x && ty == y)a[p][np] += (1 - pr[tx]) / d[tx] * pr[y]; else if(tx != x && ty != y)a[p][np] += (1 - pr[tx]) / d[tx] * (1 - pr[ty]) / d[ty]; } } gauss(); for(int i=1;i<=n;i++) { int fd = f(i,i); printf("%.6lf ",a[fd][n * n + 1] / a[fd][fd]); } }
bzoj2337 XOR 和路径
一个无向图,从 $1$ 出发每次随机选一条出边走,走到 $n$ 停止,求经过每条边权异或和的期望
$n \leq 100$
sol:
XOR 的期望...XOR 看起来是整数,期望看起来是小数,没法直接算(两个小数没法 XOR )
可以拆开每一位,算出每一位最终结果的期望,再按位值加起来就可以了
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 310; int n,m; int d[maxn];double a[maxn][maxn]; int first[maxn],to[maxn * maxn],nx[maxn * maxn],val[maxn * maxn],cnt; inline void add(int u,int v,int w) { to[++cnt] = v; nx[cnt] = first[u]; first[u] = cnt; val[cnt] = w; d[u]++; } void gauss() { int now=1,tot = n; for(int i=1;i<=tot;i++) { int j; for(j=now;!a[j][now]&&j<=tot;j++); for(int k=1;k<=tot+1;k++)swap(a[now][k],a[j][k]); for(int j=1;j<=tot;j++) if(j!=now) { double t=a[j][now]/a[now][now]; for(int k=1;k<=tot+1;k++) a[j][k]-=t*a[now][k]; } now++; } } int main() { n = read(),m = read(); for(int i=1;i<=m;i++) { int u = read(),v = read(),w = read(); add(u,v,w); if(u != v)add(v,u,w); }double ans = 0; for(int T=0;T<=30;T++) { memset(a,0,sizeof(a)); for(int i=1;i<n;i++)a[i][i] = 1.0; for(int x=1;x<n;x++) { for(int i=first[x];i;i=nx[i]) { if(val[i] & (1 << T))a[x][to[i]] += (1.0 / d[x]),a[x][n + 1] += (1.0 / d[x]); else a[x][to[i]] -= (1.0 / d[x]); } }a[n][n] = 1; gauss(); ans += (1 << T) * (a[1][n + 1] / a[1][1]); } printf("%.3lf\n",ans); }