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\)。

把步数乘上对应概率加起来就是期望值。

高斯消元

然后我们列出了这样的式子

\[dp[i][j]=\sum_{v\in s[j]}[(dp[i][v]+1)\cdot 概率]+\sum_{v\in s[j]}[(dp[k][v]+1)\cdot 概率]
\]

变形一下就是

\[dp[i][j]-\sum_{v\in s[j]} dp[i][v]\cdot\frac 1 {s_j} \cdot \left[p[j]\cdot \frac {\sum {a[i]\cdot (a[i]-1)}}{n\cdot(n-1)}+(1-p[j])\right]\\
=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 + 高斯消元)的更多相关文章

  1. HDU 5755 Gambler Bo(高斯消元)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5755 [题目大意] 一个n*m由0,1,2组成的矩阵,每次操作可以选取一个方格,使得它加上2之后对 ...

  2. HDU 4818 RP problem (高斯消元, 2013年长春区域赛F题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4818 深深地补一个坑~~~ 现场赛坑在这题了,TAT.... 今天把代码改了下,过掉了,TAT 很明显 ...

  3. ACM学习历程—HDU 3949 XOR(xor高斯消元)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 题目大意是给n个数,然后随便取几个数求xor和,求第k小的.(重复不计算) 首先想把所有xor的 ...

  4. hdu 5833 Zhu and 772002 高斯消元

    Zhu and 772002 Problem Description Zhu and 772002 are both good at math. One day, Zhu wants to test ...

  5. 2014多校第一场J题 || HDU 4870 Rating(DP || 高斯消元)

    题目链接 题意 :小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100,告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的 ...

  6. HDU 3571 N-dimensional Sphere(高斯消元 数论题)

    这道题算是比较综合的了,要用到扩展欧几里得,乘法二分,高斯消元. 看了题解才做出来orz 基本思路是这样,建一个n*(n-1)的行列式,然后高斯消元. 关键就是在建行列式时会暴long long,所以 ...

  7. HDU 3949 XOR ——线形基 高斯消元

    [题目分析] 异或空间的K小值. 高斯消元和动态维护线形基两种方法都试了试. 动态维护更好些,也更快(QAQ,我要高斯消元有何用) 高斯消元可以用来开拓视野. 注意0和-1的情况 [代码] 高斯消元 ...

  8. HDU 3949:XOR(高斯消元+线性基)

    题目链接 题意 给出n个数,问这些数的某些数xor后第k小的是谁. 思路 高斯消元求线性基. 学习地址 把每个数都拆成二进制,然后进行高斯消元,如果这个数字这一位(列)有1,那么让其他数都去异或它,消 ...

  9. HDU 3949 XOR [线性基|高斯消元]

    目录 题目链接 题解 代码 题目链接 HDU 3949 XOR 题解 hdu3949XOR 搞死消元找到一组线性无关组 消出对角矩阵后 对于k二进制拆分 对于每列只有有一个1的,显然可以用k的二进制数 ...

随机推荐

  1. cssie7.0兼容

    http://www.w3dev.cn/article/20140328/IE7-float-left-touch-border-inner-break.aspx

  2. el标签将时间戳转换为特定格式以及将数值保留特定小数

    jsp中/el表达式中将后台传来的时间戳格式化为年月日时分秒 1.引入相关标签库 <%@taglib prefix="c" uri="http://java.sun ...

  3. cmake 添加头文件目录,链接动态、静态库(转载)

    来源网址:http://www.cnblogs.com/binbinjx/p/5626916.html 罗列一下cmake常用的命令. CMake支持大写.小写.混合大小写的命令. 1. 添加头文件目 ...

  4. WPF制作带明细的环形图表

    效果 明细用Popup实现的,录gif时,Popup显示不出来,不知道为什么,所以静态图凑合看吧 大体思路 图表使用Arc+Popup实现 图表分为两部分,一是环形部分,一是标注的明细部分. 环形部分 ...

  5. html绝对路径,相对路径

    .com/eat.php中引用.com/includes/headrt.php的话写includes/header.php .com/service/eat.php中引用.com/includes/h ...

  6. Mysql双主热备+LVS+Keepalived高可用操作记录

    MySQL复制能够保证数据的冗余的同时可以做读写分离来分担系统压力,如果是主主复制还可以很好的避免主节点的单点故障.然而MySQL主主复制存在一些问题无法满足我们的实际需要:未提供统一访问入口来实现负 ...

  7. A. Make a triangle!

    题意 给你三条边a,b,c问使得构成三角形,需要增加的最少长度是多少 思路 数学了啦 代码 #include<bits/stdc++.h> using namespace std; #de ...

  8. 第六周分析Linux内核创建一个新进程的过程

    潘恒 原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 task_struct结构: ...

  9. Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥

    (一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用 ...

  10. Opentsdb 启动显示配置文件不存在

    今天 重新启动opentsdb  出现本地配置文件不存在   这不知道  我查了一下官网 了解到 You can use the --config command line argument to s ...