[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以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一 ...
随机推荐
- bzoj2876 [NOI2012]骑行川藏(拉格朗日乘数法)
题目描述 蛋蛋非常热衷于挑战自我,今年暑假他准备沿川藏线骑着自行车从成都前往拉萨.川藏线的沿途有着非常美丽的风景,但在这一路上也有着很多的艰难险阻,路况变化多端,而蛋蛋的体力十分有限,因此在每天的骑行 ...
- PHP判断SQL语句是否合法:mysqli_error()
假设现在有条update语句,有时候update语句正确,但是受影响的行数是0. 那么怎么判断这条SQL语句到底是否正确?使用 mysqli_error($Conn); create table us ...
- cryptojs的使用
项目中经常会遇到加密解密的需求,这里有一个js库非常好用,就是crypto-js.下面记录一下使用方法. 首先,安装js库 npm install crypto-js --save 然后,在项目中使用 ...
- 【Javascript】在文本框光标处插入文字并定位光标 (转)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java经典编程题50道之二十九
求一个3*3矩阵对角线元素之和. public class Example29 { public static void main(String[] args) { int[][] ...
- 搭建VUE项目的准备(利用vue-cli来构建项目)
首先需要明确的是:Vue.js 不支持 IE8 及其以下 IE 版本,一般用与移动端,基础:开启最高权限的DOS命令(否则会出现意外的错误提示) 注意:个人小推荐如果我们不知道如何才能开启最高权限 ...
- 微信小程序(一)
开发流程 注册微信小程序并申请微信支付-->制作小程序-->上传并提交审核-->审核通过,小程序上线 开发微信小程序需要准备 企业公众号(被认证)以及申请小程序.微信开发技术.S ...
- JavaScript 一个进行枚举选择的jquery插件(仿easyui风格)
某次做项目要实现一个功能: 按星期选择一个连续的时间范围 比如:周一到周五,周六到周日 或 周六到周三 聪明的朋友马上想出办法:用两个选项为周一到周日的下拉列表实现,对 那样可以,但是我觉得不够友好, ...
- HDU - 2112 HDU Today Dijkstra
注意: 1.去重边 2.终点和起点一样,应当输出0 3.是无向图 AC代码 #include <cstdio> #include <cmath> #include <al ...
- mysql忘记密码解决的办法
[很管用]忘记mysql root密码解决办法 1.编辑MySQL配置文件: 首先停止mysql服务, 然后开始编辑mysql配置文件:vi /etc/my.cnf在[mysqld]配置段添加如下一行 ...