【 HDU 4936 】Rainbow Island (hash + 高斯消元)
BUPT2017 wintertraining(15) #5B
HDU - 4936
2014 Multi-University Training Contest 7 F
题意
直接看官方的题意和题解吧(来自:2014年多校的题解博客)。
题解
官方的不够细,我再梳理一下吧。
预处理:
首先dfs出所有可能的联通块状态,这个状态只考虑共几个联通块,每个联通块里几个岛,不考虑是哪些岛。然后对每个状态hash一下,编个号。根据我们dfs的顺序,1号状态是全部独立,cnt号状态是全部联通。
\(mg[i][x][y]\)为合并i状态的第x和第y个联通块得到的状态编号,可以求出来。
dp
我用\(dp[i][j]\)保存第i号状态,人在第j个岛上,到达目标的期望步数。
那么\(dp[1][1]\)就是答案,\(dp[cnt][i]\)都是0。
然后两种转移就是
1. 状态不变,i状态的j岛转移到v岛
步数就是\(dp[i][v]+1\)。
到达v岛的概率是\(\frac 1 {s_j}\)
如果产生了彩虹(p[j]),那么必须是连接同一联通块的岛。
a[i]是第i个联通块的岛的数量,\(C_{a[i]}^2\)种方案是不改变状态的,总方案是\(C_{n}^{2}\),于是彩虹连接同一联通块的概率就是\(\frac {\sum {a[i]*(a[i]-1)}}{n*(n-1)}\)。
否则不产生彩虹(1-p[j]),状态一定不变。
2. 状态改变,i状态的j岛转移到k状态的v岛
步数是\(dp[k][v]+1\)。
把步数乘上对应概率加起来就是期望值。
高斯消元
然后我们列出了这样的式子
\]
变形一下就是
=1+\sum_{\substack{v \in s[j]\\k=mg[i][x][y]}} dp[k][v]\cdot\frac 1 {s_j} \cdot \frac{a[x]\cdot a[y]}{(n\cdot (n-1)/2)}
\]
右边的dp是已经求得的,所以是个常数。左边的dp[i][j]作为未知数,j从1到n有n个这样的方程,n个未知数,可以高斯消元来求解。
ps. 这次的sb错,调了好一会儿:直接把整型数相乘然后去除以浮点数。另外这题好难啊,我想了很久,最后还是看官方题解加上看别人代码理解才写出来。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define N 22
#define M 1000007
using namespace std;
int cas,t,n,cnt,a[N];
int f[M+1],mg[700][N][N];
//f[code]:code对应的状态
//mg[s][x][y]:状态s的第x和第y个合并后的状态
double p[N],dp[700][N],g[N][N];
//dp[st][i],当前状态st,人在第i个岛上,到达目标状态的期望值
vector<int>s[N];
struct sta{
int a[N],tot;
}st[700];
int code(sta t){
int b=t.tot;
for(int i=1;i<=t.tot;i++)
b=(b*233%M+t.a[i])%M; //hash
return b;
}
void dfs(int d,int k,int sum){
if(sum==n){
sta &t=st[++cnt];
t.tot=d-1;
for(int i=1;i<d;i++)
t.a[i]=a[i];
f[code(t)]=cnt;
return;
}
for(int i=k;i<=n-sum;i++)
dfs(d+1,a[d]=i,sum+i);
}
int merge(sta t,int x,int y){
t.a[x]+=t.a[y];
swap(t.a[y],t.a[t.tot--]);
sort(t.a+1,t.a+t.tot+1);
return f[code(t)];
}
void pre(){
//求出所有可能的状态并hash处理,求出合并两个联通块后对应的状态
cnt=0;
dfs(1,1,0);
for(int i=1;i<=cnt;i++)
for(int x=1;x<st[i].tot;x++)
for(int y=x+1;y<=st[i].tot;y++)
mg[i][x][y]=merge(st[i],x,y);
}
void gauss(double x[]){
for(int i=1;i<=n;i++){
int r=i;
while(!g[r][i]&&r<=n)r++;
if(r>n)return;
swap(g[r],g[i]);
for(int j=i+1;j<=n;j++){
double t=g[j][i]/g[r][i];
for(int k=1;k<=n+1;k++)
g[j][k]-=t*g[r][k];
}
}
for(int i=n;i;i--)if(g[i][i]){//注意判断
x[i]=g[i][n+1]/g[i][i];
for(int j=1;j<i;j++)
g[j][n+1]-=g[j][i]*x[i];
}
}
void work(){
memset(dp,0,sizeof dp);
for(int i=cnt-1;i>=1;i--){
memset(g,0,sizeof g);
for(int j=1;j<=n;j++){
double b=1;
for(int x=1;x<st[i].tot;x++)
for(int y=x+1;y<=st[i].tot;y++){
int k=mg[i][x][y];
double ps=p[j]*st[i].a[x]*st[i].a[y]/(n*(n-1)/2)/s[j].size();
for(int u=0;u<s[j].size();u++){
int v=s[j][u];
b+=dp[k][v]*ps;
}
}
g[j][j]=1;
g[j][n+1]=b;
double ps=0;
for(int x=1;x<=st[i].tot;x++)
ps+=st[i].a[x]*(st[i].a[x]-1);//连接同一联通块的岛的彩虹个数*2
ps/=n*(n-1);//除以 2*总的彩虹个数(n*(n-1)/2)
ps=(ps*p[j]+1-p[j])/s[j].size();
for(int u=0;u<s[j].size();u++){
int v=s[j][u];
g[j][v]-=ps;
}
}
gauss(dp[i]);
}
}
int main() {
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf",&p[i]),s[i].clear();
for(int i=1,t,v;i<=n;i++){
scanf("%d",&t);
while(t--){
scanf("%d",&v);
s[i].push_back(v);
}
}
pre();
work();
printf("Case #%d: %f\n",++cas,dp[1][1]);
}
return 0;
}
【 HDU 4936 】Rainbow Island (hash + 高斯消元)的更多相关文章
- HDU 5755 Gambler Bo(高斯消元)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5755 [题目大意] 一个n*m由0,1,2组成的矩阵,每次操作可以选取一个方格,使得它加上2之后对 ...
- HDU 4818 RP problem (高斯消元, 2013年长春区域赛F题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4818 深深地补一个坑~~~ 现场赛坑在这题了,TAT.... 今天把代码改了下,过掉了,TAT 很明显 ...
- ACM学习历程—HDU 3949 XOR(xor高斯消元)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 题目大意是给n个数,然后随便取几个数求xor和,求第k小的.(重复不计算) 首先想把所有xor的 ...
- hdu 5833 Zhu and 772002 高斯消元
Zhu and 772002 Problem Description Zhu and 772002 are both good at math. One day, Zhu wants to test ...
- 2014多校第一场J题 || HDU 4870 Rating(DP || 高斯消元)
题目链接 题意 :小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100,告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的 ...
- HDU 3571 N-dimensional Sphere(高斯消元 数论题)
这道题算是比较综合的了,要用到扩展欧几里得,乘法二分,高斯消元. 看了题解才做出来orz 基本思路是这样,建一个n*(n-1)的行列式,然后高斯消元. 关键就是在建行列式时会暴long long,所以 ...
- HDU 3949 XOR ——线形基 高斯消元
[题目分析] 异或空间的K小值. 高斯消元和动态维护线形基两种方法都试了试. 动态维护更好些,也更快(QAQ,我要高斯消元有何用) 高斯消元可以用来开拓视野. 注意0和-1的情况 [代码] 高斯消元 ...
- HDU 3949:XOR(高斯消元+线性基)
题目链接 题意 给出n个数,问这些数的某些数xor后第k小的是谁. 思路 高斯消元求线性基. 学习地址 把每个数都拆成二进制,然后进行高斯消元,如果这个数字这一位(列)有1,那么让其他数都去异或它,消 ...
- HDU 3949 XOR [线性基|高斯消元]
目录 题目链接 题解 代码 题目链接 HDU 3949 XOR 题解 hdu3949XOR 搞死消元找到一组线性无关组 消出对角矩阵后 对于k二进制拆分 对于每列只有有一个1的,显然可以用k的二进制数 ...
随机推荐
- Redis详解(六)------ RDB 持久化
前面我们说过,Redis 相对于 Memcache 等其他的缓存产品,有一个比较明显的优势就是 Redis 不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,has ...
- Luogu4899 IOI2018 Werewolf 主席树、Kruskal重构树
传送门 IOI强行交互可还行,我Luogu的代码要改很多才能交到UOJ去-- 发现问题是对边权做限制的连通块类问题,考虑\(Kruskal\)重构树进行解决. 对于图上的边\((u,v)(u<v ...
- BootStrap学习(2)_下拉菜单&按钮组
一.下拉菜单 1.基本下拉菜单 如需使用下列菜单,只需要在class .dropdown 内加上下拉菜单即可.下面的实例演示了基本的下拉菜单: <!DOCTYPE html> <ht ...
- Linux性能评测工具之一:gprof篇
这些天自己试着对项目作一些压力测试和性能优化,也对用过的测试工具作一些总结,并把相关的资料作一个汇总,以便以后信手拈来! 1 简介 改进应用程序的性能是一项非常耗时耗力的工作,但是究竟程序中是哪些函数 ...
- Hexo博客搭建以及Next主题美化的经验之谈
这并不是一篇博客搭建教程.内容主要包含个人对于Hexo博客搭建的心得,Next6.0主题美化的部分建议,以及摘录一些各种用于博客搭建的link. 在博客园3年6个月,确实也学到了很多,博客园也是目前为 ...
- 记录:EM 算法估计混合高斯模型参数
当概率模型依赖于无法观测的隐性变量时,使用普通的极大似然估计法无法估计出概率模型中参数.此时需要利用优化的极大似然估计:EM算法. 在这里我只是想要使用这个EM算法估计混合高斯模型中的参数.由于直观原 ...
- Linux系统下本地yum镜像源环境部署-完整记录
之前介绍了Linux环境下本地yum源配置方法,不过这个是最简单最基础的配置,在yum安装的时候可能有些软件包不够齐全,下面说下完整yun镜像源系统环境部署记录(yum源更新脚本下载地址:https: ...
- 几何学观止(Riemann流形部分)
上承这个页面,相较之前,增加了古典的曲线曲面论,这部分介绍得很扼要,Riemann流形介绍得也很快,花了仅仅30页就介绍到了Gauss-Bonnet公式.同时配上了提示完整的习题. 几何学观止-Rie ...
- VS2013软件的安装和单元测试
VS2013是什么? 微软在Builder 2013开发者大会上发布了Visual Studio 2013预览版,并且发布其程序组件库.NET 4.5.1的预览版.该软件已于北京时间2013年11月1 ...
- Scrum Meeting NO.8
Scrum Meeting No.8 1.会议内容 2.任务清单 徐越 序号 近期的任务 进行中 已完成 1 代码重构:前端通讯模块改为HttpClient+Json √ 2 添加对cookies的支 ...