[HNOI2011]XOR和路径 && [HNOI2013]游走
[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]游走的更多相关文章
- [HNOI2011]XOR与路径
		
https://zybuluo.com/mdeditor#1094266 标签(空格分隔): 高斯消元 期望 题面 从 1 号节点开始,以相等的概率,随机选择与当前节点相关联的某条边,并沿这条边走到下 ...
 - BZOJ2337: [HNOI2011]XOR和路径
		
题解: 异或操作是每一位独立的,所以我们可以考虑每一位分开做. 假设当前正在处理第k位 那令f[i]表示从i到n 为1的概率.因为不是有向无环图(绿豆蛙的归宿),所以我们要用到高斯消元. 若有边i-& ...
 - BZOJ 2337: [HNOI2011]XOR和路径 [高斯消元 概率DP]
		
2337: [HNOI2011]XOR和路径 题意:一个边权无向连通图,每次等概率走向相连的点,求1到n的边权期望异或和 这道题和之前做过的高斯消元解方程组DP的题目不一样的是要求期望异或和,期望之间 ...
 - [HNOI2011]XOR和路径
		
题面在这里 题意:给定一个无向图,从1号节点出发,每次等概率选择连接该节点的一条边走到另一个节点,到达n号节点时,将走过的路径上的所有边权异或起来,求这个异或和的期望 sol 一道期望大火题(表示看了 ...
 - 【BZOJ 2337】 2337: [HNOI2011]XOR和路径(概率DP、高斯消元)
		
2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1170 Solved: 683 Description ...
 - 【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径
		
2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 682 Solved: 384[Submit][Stat ...
 - bzoj 3143: [Hnoi2013]游走 高斯消元
		
3143: [Hnoi2013]游走 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1026 Solved: 448[Submit][Status] ...
 - BZOJ 2337: [HNOI2011]XOR和路径( 高斯消元 )
		
一位一位考虑异或结果, f(x)表示x->n异或值为1的概率, 列出式子然后高斯消元就行了 --------------------------------------------------- ...
 - [补档][Hnoi2013]游走
		
[Hnoi2013]游走 题目 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一 ...
 
随机推荐
- NOIP2017滚粗记
			
NOIP2017滚粗记 扯淡 考完联赛后一直在搞文化... 联赛过去了不知道多少天了才来写这东西.... Day0 早自习知道了要期中考试. 感觉心态炸裂了. 上午在乱敲板子.... 打了一堆莫名其妙 ...
 - WordPress 实现附件上传自动重命名但不改变附件标题
			
WordPress 上传媒体文件时,默认会保持文件名不变.如果上传文件名中包含中文字符,则会造成部分浏览器显示的文件 URL 疑似乱码甚至无法访问.网上流行较广的是通过注册 wp_handle_up ...
 - ELF哈希技术
			
ELFhash详情见点击打开链接 代码如下: unsigned int ELFhash(char *str) { unsigned int hash=0; unsigned int x=0; whil ...
 - visual studio调试功能简述
			
vs调试简述 1.调试功能简述 vs提供了很强大的调试功能,能够让我们一步步执行中找到每个变量的值,便于查错改错.很多IDE都有调试功能,在使用调试功能时,记得先创建一个项目,哪怕是一个文件,也创建一 ...
 - 学生信息管理系统(c语言)
			
①注意: 程序中使用了sleep()函数.system()函数 关于 sleep() 函数 sleep() 函数的头文件和用法会因环境的不同而有所不同. 具体见-sleep()函数功能及用法 关于sy ...
 - 阻止微信浏览器/QQ浏览器长按弹框“在浏览器打开”
			
这个弹框实际上等同于PC环境下的鼠标右键的弹框,因此只要禁止页面的弹框事件就能完美屏蔽该弹框对我们功能带来的影响.程序代码如下: document.oncontextmenu=function(e){ ...
 - linux iptables配置
			
防火墙硬件防火墙软件防火墙: 应用层防火墙 网络层防火墙:linux包过滤防火墙linux包过滤防火墙netfilter:位于linux内核中的包过滤功能体系,称为linux防火墙的"内核态 ...
 - Nodejs的运行原理-libuv篇
			
前言 这应该是Nodejs的运行原理的第7篇分享,这篇过后,短时间内不会再分享Nodejs的运行原理,会停更一段时间,PS:不是不更,而是会开挖新的坑,最近有在研究RPG Maker MV,区块链,云 ...
 - 使用sql语句获取数据库表的信息
			
下面的sql语句可以查看表的信息.其中modify_date和create_date可以根据表的修改时间来查看.如果不需要删除后,就能看到所有表的字段信息 ) PERCENT d.name AS 表名 ...
 - Android动态改变App在Launcher里面的icon
			
如果呆萌的产品童鞋让你动态更换App在Launcher里面的Icon,你怎么回答他,下文就提出一种实现该效果的方法. 原理1--activity-alias 在AndroidMainifest中,有两 ...