[HNOI2011]XOR和路径

题目大意

具体题目:戳我
题目:
给定一个n个点,m条边的有重边、有自环的无向图,其中每个边都有一个边权。
现在随机选择一条1到n的路径,路径权值为这条路径上所有边权的异或和。
特别注意,如果同一条边在路径中经过了多次,那么路径权值也要异或对应次数的边权。
请回答 这条路径的 期望权值 为多少。
数据范围:\(n \leq 100\) , \(m \leq 10^4\) 。对于所有边,\(val_E \leq 10^9\)。

思路及解法

A

首先,求异或问题拆成每一个二进制位来算这都是老套路了。
本题也是一样,把每一个边权拆成二进制的每一位。
那么此时我们只用考虑这一位为\(1\)的概率,最后贡献乘上一个对应系数即可。
倒着\(DP\) , 设\(f[u]\)表示\(u\)到\(n\)路径异或和为\(1\)的概率。
转移还是挺简单的:
\[f[u] = \sum \frac{f[v]}{degree[u]}[E(u,v)=0] + \sum \frac{(1-f[v])}{degree[u]}[E(u,v)=1]\]
然后你会发现这样转移不了,因为对应的\(f[v]\)可能还未确定。
所以\(f[x]\)之间是互相影响的,没有办法直接转移。 怎么办呢?

B

本题最超神的地方来了。
我们观察每一个方程:
\[f[u] = \sum \frac{f[v]}{degree[u]}[E(u,v)=0] + \sum \frac{(1-f[v])}{degree[u]}[E(u,v)=1]\]
移项:
\[f[u]+\sum \frac{f[v]}{degree[u]}[E(u,v)=1] - \sum \frac{f[v]}{degree[u]}[E(u,v)=0] = \sum [E(u,v)=1]\]
把每一个\(f[i]\)看做一个未知数\(x_i\),那么刚好有\(n\)个方程。
高斯消元即可(太神奇了原来高斯消元还可以这么用).......

实现代码:

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 105
using namespace std;

struct Road{int to,next,val;}t[2*_*_];
double ans , f[_][_] , deg[_]; int head[_],d[_],n,m,cnt;

IL void Build(RG int jd){
    memset(f,0,sizeof(f));
    for(RG int u = 1; u < n; u ++){   //注意n的方程要特判!!
        f[u][u] = 1.0;
        for(RG int e = head[u]; e ; e = t[e].next){
            RG int v = t[e].to , w = ((t[e].val>>jd)&1);
            if(w!=0)f[u][n+1] += 1.0/deg[u] , f[u][v] += 1.0/deg[u];
            else f[u][v] -= 1.0/deg[u];
        }
    }f[n][n] = 1.0;  return;
}

IL void Gauss(){
    for(RG int j = 1; j <= n; j ++){
        RG int rgt = 0;
        for(RG int i = j; i <= n; i ++)
            if(f[i][j]){rgt = i; break;}
        if(!rgt)continue;
        if(rgt ^ j)swap(f[rgt],f[j]);
        for(RG int i = j+1; i <= n; i ++){
            RG double div = f[i][j] / f[j][j];
            for(RG int k = 1; k <= n+1; k ++)
                f[i][k] -= 1.0 * f[j][k] * div;
        }
    }
    for(RG int j = n; j >= 1; j --){
        f[j][n+1] = f[j][n+1] / f[j][j];
        for(RG int i = j-1; i >= 1; i --)
            f[i][n+1] -= 1.0*f[i][j] * f[j][n+1];
    }return;
}

int main(){
    cin >> n >> m;
    for(RG int i = 1; i <= m; i ++){
        RG int u,v,w;
        cin >> u >> v >> w;
        t[++cnt] = (Road){v,head[u],w} , head[u] = cnt , d[u]++;
        if(u^v)t[++cnt] = (Road){u,head[v],w} , head[v] = cnt , d[v]++;
        //特别注意如果这里是自环只能连一条边。
    }
    for(RG int i = 1; i <= n; i ++)deg[i] = d[i];
    ans = 0;
    for(RG int e = 0; e <= 30; e ++){
        Build(e);  Gauss();
        double nm = 1.0*(1<<e);
        ans = ans + 1.0*nm*f[1][n+1];
    }
    printf("%.3lf",ans); return 0;
}

补充题:[HNOI2013]游走

然而,你以为这样就完了吗.......
这里还有一道更加恶心的:[HNOI2013]游走

壮哉我大湖南,尽出这种毒瘤题........

题目大意:

一个无向连通图,顶点从\(1\)编号到\(N\),边从\(1\)编号到\(M\)。
小Z在该图上进行随机游走,初始时小Z在\(1\)号顶点,
每一步小Z以相等的概率随机选择当前顶点的某条边,
沿着这条边走到下一个顶点,获得等于这条边的编号的分数。
当小Z到达\(N\)号顶点时游走结束,总分为所有获得的分数之和。
现在,请你对这\(M\)条边进行编号,使得小Z获得的总分的期望值最小。
数据范围:\(N\leq 500\) , \(M\leq 100000\)

题目解法:

这题作为补充就不写的那么详细了,那个贪心直接跳过。
关键的一步:把求边的概率转换到求点的概率。
假设一个点\(x\)在\(1\)到\(n\)的路径上被经过的概率为\(p_x\) , 那么
\[p_{<u,v>} = \frac{p_{u}}{degree[u]} + \frac{p_{v}}{degree[v]} \]
然后就只要求\(p_u\)了。 显然有方程式: \(p_u = \sum \frac{p_v}{degree[v]}\)
移一下项得到:\(p_u - \sum \frac{p_v}{degree[v]} = 0\) ;与上题类似高斯消元即可。
然后注意一下子边界问题,我在代码里面详细讲了。

实现代码:

注:这题 \(Luogu\) 数据真的太卡精度了,这份代码交上去只能获得 70分。

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 505
#define eps 1e-7
using namespace std;

double fc[_][_] , deg[_] , ans[_]; int n,m;
struct Edge{
    int x1,x2; double p;
    bool operator < (const Edge &B)const{
        return p > B.p;}
}eg[2*_*_];
struct Road{int to,next;}t[_*_*2];  int head[_],cnt;

IL void Gauss(){
    for(RG int j = 1; j < n; j ++){
        RG int r = 0;
        for(RG int i = j; i < n; i ++)
            if(fc[i][j]){r = i; break;}
        if(r <= eps)continue;
        if(r ^ j)swap(fc[r] , fc[j]);
        for(RG int i = j+1; i < n; i ++){
            RG double div = (fc[i][j] / fc[j][j]);
            for(RG int k = 1; k <= n; k ++)
                fc[i][k] -= div*fc[j][k];
        }
    }
    for(RG int j = n-1; j >= 1; j --){
        ans[j] = fc[j][n] / fc[j][j];
        for(RG int i = j-1; i >= 1; i --)
            fc[i][n] -= ans[j] * fc[i][j];
    }return;
}

int main(){
    cin >> n >> m;
    for(RG int i = 1; i <= n; i ++)
        fc[i][i] = 1.0;
    for(RG int sq = 1; sq <= m; sq ++){
        RG int u , v;
        cin >> u >> v;
        eg[sq] = (Edge){u,v,0};
        deg[u] += 1.0 ; if(u^v)deg[v] += 1.0;
        t[++cnt] = (Road){v,head[u]}; head[u] = cnt;
        if(u ^ v)t[++cnt] = (Road){u,head[v]}; head[v] = cnt;
    }
    for(RG int u = 1; u < n; u ++){
        for(RG int i = head[u]; i; i = t[i].next){
            RG int v = t[i].to;
            if(v ^ n)fc[u][v] -= 1.0/deg[v];
        }
    }
    fc[1][n] = 1.0;
    //注:由于到了n之后游走就结束了,所以为了不影响其它方程的求解,f[n] = 0;
    //为了省空间,把原来的常数项(答案项)向左移了一个移到了fc[i][n];
    //由于1、n是一定会经过的,所以它们的答案为1.0,即fc[1][n] = fc[n][n] = 1.0;
    Gauss();
    for(RG int i = 1,u,v; i <= m; i ++)
        u = eg[i].x1,v = eg[i].x2 ,
        eg[i].p = ans[u]/deg[u] + ans[v]/deg[v];
    sort(eg+1,eg+m+1);
    RG double res =0,oo;
    for(RG int i = 1; i <= m; i ++)
        oo = i , res = res + 1.0*oo*eg[i].p; //p从大到小排序。
    printf("%.3lf",res); return 0;
}

[HNOI2011]XOR和路径 && [HNOI2013]游走的更多相关文章

  1. [HNOI2011]XOR与路径

    https://zybuluo.com/mdeditor#1094266 标签(空格分隔): 高斯消元 期望 题面 从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下 ...

  2. BZOJ2337: [HNOI2011]XOR和路径

    题解: 异或操作是每一位独立的,所以我们可以考虑每一位分开做. 假设当前正在处理第k位 那令f[i]表示从i到n 为1的概率.因为不是有向无环图(绿豆蛙的归宿),所以我们要用到高斯消元. 若有边i-& ...

  3. BZOJ 2337: [HNOI2011]XOR和路径 [高斯消元 概率DP]

    2337: [HNOI2011]XOR和路径 题意:一个边权无向连通图,每次等概率走向相连的点,求1到n的边权期望异或和 这道题和之前做过的高斯消元解方程组DP的题目不一样的是要求期望异或和,期望之间 ...

  4. [HNOI2011]XOR和路径

    题面在这里 题意:给定一个无向图,从1号节点出发,每次等概率选择连接该节点的一条边走到另一个节点,到达n号节点时,将走过的路径上的所有边权异或起来,求这个异或和的期望 sol 一道期望大火题(表示看了 ...

  5. 【BZOJ 2337】 2337: [HNOI2011]XOR和路径(概率DP、高斯消元)

    2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1170  Solved: 683 Description ...

  6. 【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径

    2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 682  Solved: 384[Submit][Stat ...

  7. bzoj 3143: [Hnoi2013]游走 高斯消元

    3143: [Hnoi2013]游走 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1026  Solved: 448[Submit][Status] ...

  8. BZOJ 2337: [HNOI2011]XOR和路径( 高斯消元 )

    一位一位考虑异或结果, f(x)表示x->n异或值为1的概率, 列出式子然后高斯消元就行了 --------------------------------------------------- ...

  9. [补档][Hnoi2013]游走

    [Hnoi2013]游走 题目 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一 ...

随机推荐

  1. Es6 Symbol.iterator

    Symbol.iterator 为每一个对象定义了默认的迭代器.该迭代器可以被 for...of 循环结构使用. --描述 当需要迭代一个对象的时候(比如在 for...of 循环的开始时),它的 @ ...

  2. 小笔记:Timer定时间隔时间操作

    小笔记:Timer定时间隔时间操作,后面有时间再补充和完善: public class TimingSvc { /// <summary> /// 定时器,执行定时任务 /// </ ...

  3. linear-grident的属性和使用以及对颜色后面参数(百分比)的理解

    linear-grident的属性和使用   css3新增Gradient属性,用来增加渐变的效果,渐变分为线性渐变 linear-grident 和 径向渐变 radial-grident,这篇文章 ...

  4. VSCode插件MSSQL教程(昨天提了一下)

    推荐一个跨平台SQL IDE:https://docs.microsoft.com/zh-cn/sql/sql-operations-studio/download 什么数据库都木有(系统自带的不算) ...

  5. 试用MarkDown

    自定义界面风格 可以在设置中选择日间,或者夜间模式进行定义.具体的定义项的说明,可以查看菜单栏 (Windows版本位于托盘按钮上) 自定义的帮助. MarkEditor几乎所有跟色彩有关的界面,都已 ...

  6. ASP.NET CORE MVC 实现减号分隔(Kebab case)样式的 URL

    ASP.NET CORE MVC 中,默认的 Route 模板是: /{controller}/{action}  .我们可以通过开启 URL 小写转换将 URL 变为小写,但此方式在 Control ...

  7. Mysql的sql_mode

    (一) 基本介绍 set sql_mode="",即强制不设定MySql模式(如不作输入检测.错误提示.语法模式检查等)应该能提高性能,但有如下问题: 如果插入了不合适数据(错误类 ...

  8. Angular Universal(统一平台)笔记

    angular官网高级文档AngularUniversal部分的翻译总结,这东西在angular4开始正式被官方支持了,目前其实支持的服务器端还没有很多,但好歹包括了node和DotNetCore,算 ...

  9. 四级地址插件升级改造(京东商城地址选择插件)city-picker

    最近公司做的项目要和京东的数据做对接,所以要做个类似京东商品的详情页.页面的数据,是可以从京东接口获取到的,但是地址插件选择的效果需要自己实现.前端的同事在之前的项目中,已经选择了一款地址插件(cit ...

  10. Extjs 4.0 Tab页

    1.JSON代码 Ext.MyTabs=Ext.extend(Ext.TabPanel ,{ xtype:"tabpanel", activeTab:2, width:694, h ...