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. Codeforces 718C solution

    C. Sasha and Array   time limit per test :  5 seconds memory limit per test :  256 megabytes Descrip ...

  2. LNMP V1.4一键快速部署Let's Encrypt免费SSL证书

    老左年前在"军哥LNMP V1.4测试版一键脚本安装以及功能上的升级体验"已经简单的体验到目前还没有正式版本的V1.4版本,理论上会在今年儿童节正式上线.从体验和实际的版本变动文档 ...

  3. CRC---循环冗余校验

    typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned short uInt16; uint crc; // ...

  4. 【nodejs】让nodejs像后端mvc框架(asp.net mvc )一样处理请求--自动路由篇(1/8)【route】

    文章目录 前情概要 在使用express框架开发的时候,每加一个请求,都在增加一条route请求规则,类似于下面的代码,很烦有木有! app.use('/myroute path', (req, re ...

  5. github使用心得和链接

    在本次使用github过程中,刚打开github主界面的时候,吓了一跳,满眼的英文加上各种没用过的命令,真是一个头两个大,废话不多说,下面我就说一下我在使用github过程中遇到的两个问题.: 问题一 ...

  6. Atcoder D - Knapsack 1 (背包)

    D - Knapsack 1 Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement The ...

  7. MySQL存储和获取数据

    ---恢复内容开始--- 一.MySQL存储引擎? 1.引擎定义 存储引擎其实就是如何存取数据,如何为存储的数据建立索引和如何更新.查询数据等技术的实现方法.因为在关系型数据苦中数据是以表格的形式,所 ...

  8. octave基本指令1

    octave基本指令1 注释 使用: disp 输出指令 eg: >>a = pi; >>disp(sprintf('2 decimals:%0.2f'a)) 2 decima ...

  9. mybatis 框架网站

    http://www.mybatis.org/mybatis-3/zh/index.html

  10. JavaScript封装方法,兼容参数类型为Number和String

    /** * 依据Kind确定跳转到目标列表页面. * @param kind */ function gobackByKind(kind) { var kindStr = String(kind); ...