[基本操作]高斯消元和线性基

高斯消元,就是 $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]);
    }
}
View Code

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);
}
View Code

猜你喜欢

转载自www.cnblogs.com/Kong-Ruo/p/10182284.html