@gym - 100591D@ Fox Rocks
@description@
给定 N 个点以及 P 条单向道路 Ai -> Bi,每条道路有 Ri 块石头(保证\(0 \le \lfloor\frac{Bi}{4}\rfloor-\lfloor\frac{Ai}{4}\rfloor\le 1\))。
接下来 D 天每天有一个询问,分为三类:
(1)给定 X, Y, Z,修建一条 X -> Y 且有 Z 块石头的道路。
(2)给定 X, Y,拆除 X -> Y 的原有道路。
(3)查询从 X 开始随机游走(从它的出边中等概率选一块石头,并往那条边走)可以到达 Y 的概率。
@solution@
一杯茶,一包烟,一道破题调一天。
如果我们把连续 4 个点看成一个块,则连边情况应是块内连边 + 块向下一块连边。
如果暴力着做概率 dp,可以从起点 X 出发,向后递推到 Y 所在块,每一块的块内进行高斯消元。
显然可以用线段树加速这一过程:每个结点 [l, r] 维护从第 l 个块的第 i 个点随机游走,第一次到达第 r 个块是第 r 个块的第 j 个点的概率 p[i][j]。
线段树上 merge 的过程就是个高斯消元。
最后维护一下对 Y 所在块做一个高斯消元,从 Y 所在块的第 i 个点到第 j 个点的概率 q[i][j]。
然而。。。有一个小问题。
概率 dp 的一般形式是:给定若干终止状态,保证每个点都可以到达一种终止状态,且每条转移边有一定概率。
定义 dp[i] 表示到达想要的终止状态的概率,则 dp[i] 要么游走到它可以到达的点,要么直接到达终止状态。
而这道题终止状态有 “没有出度”,“到达 Y”,“到达 Y 的下一个块”,还有一个 “进入一个无法到达 Y 的环”。
前三种可以通过 dp 的转移式子表达出来,然而最后一个并不能直接表示出来。。。
方法要么是通过简单 dfs 判断,要么还有一种特殊的判断:如果高斯消元中主对角线 = 0,则一定出现了最后一种情况。此时直接把这个方程修改成 xi = 0 的形式即可。
注意还有一个情况:询问中可能 Y 所在块 < X 所在块。此时直接输出 0。
@accepted code@
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 50000;
const double EPS = 1E-9;
double dcmp(double x) {return fabs(x) <= EPS ? 0 : (x > 0 ? 1 : -1);}
struct node{double a[4][4];};
int K;
double d[MAXN + 5];
node f[MAXN + 5], g[MAXN + 5], h[MAXN + 5];
double M[100][100];
void gauss(int n, int m) {
int r = 0, c = 0;
while( r < n && c < m ) {
if( dcmp(M[r][c]) ) {
double k = M[r][c];
for(int j=c;j<m;j++)
M[r][j] /= k;
for(int i=0;i<n;i++) {
if( i == r ) continue;
k = M[i][c];
for(int j=c;j<m;j++)
M[i][j] -= k*M[r][j];
}
r++;
}
else {
for(int j=c;j<m;j++)
M[r][j] = 0;
M[r][c] = 1;
r++;
}
c++;
}
}
void get(int x, node &p) {
for(int t=0;t<4;t++) {
for(int r=0;r<4;r++)
for(int c=0;c<4;c++)
M[r][c] = 0;
for(int r=0;r<4;r++) {
if( r == t ) {
for(int c=0;c<4;c++)
M[r][c] = (r == c);
M[r][4] = 1;
}
else {
int k = 4*x + r;
for(int c=0;c<=4;c++)
M[r][c] = (r == c);
if( d[k] == 0 ) continue;
for(int c=0;c<4;c++)
M[r][c] -= f[x].a[r][c] / d[k];
}
}
gauss(4, 4+1);
for(int s=0;s<4;s++)
p.a[s][t] = M[s][4];
}
}
struct segtree{
#define lch (x << 1)
#define rch (x << 1 | 1)
int le[4*MAXN + 5], ri[4*MAXN + 5]; node h[4*MAXN + 5];
void merge(const node &f1, const node &f2, node &f3, int m) {
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
f3.a[i][j] = 0;
for(int t=0;t<4;t++) {
for(int r=0;r<4;r++) {
int k = 4*m + r;
for(int c=0;c<4;c++) {
if( d[k] ) M[r][c] = (r == c) - f[m].a[r][c]/d[k];
else M[r][c] = (r == c);
}
if( r == t ) M[r][4] = 1;
else M[r][4] = 0;
}
gauss(4, 5);
int k = 4*m + t;
if( d[k] ) {
double a[4] = {}, b[4] = {};
for(int p=0;p<4;p++)
for(int s=0;s<4;s++)
a[p] += M[s][4]*f1.a[p][s];
for(int q=0;q<4;q++)
for(int x=0;x<4;x++)
b[q] += g[m].a[t][x]/d[k]*f2.a[x][q];
for(int p=0;p<4;p++)
for(int q=0;q<4;q++)
f3.a[p][q] += a[p]*b[q];
//f3.a[p][q] += M[s][4]*div(g[m].a[t][x], d[k])*f1.a[p][s]*f2.a[x][q];
}
}
}
void pushup(int x) {
int m = (le[x] + ri[x]) >> 1;
merge(h[lch], h[rch], h[x], m);
}
void build(int x, int l, int r) {
le[x] = l, ri[x] = r;
if( l == r ) {
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
h[x].a[i][j] = (i == j);
return ;
}
int m = (le[x] + ri[x]) >> 1;
build(lch, l, m), build(rch, m + 1, r);
pushup(x);
}
void update(int x, int p) {
if( le[x] == ri[x] ) return ;
int m = (le[x] + ri[x]) >> 1;
if( p <= m ) update(lch, p);
else update(rch, p);
pushup(x);
}
node query(int x, int ql, int qr) {
if( ql <= le[x] && ri[x] <= qr )
return h[x];
int m = (le[x] + ri[x]) >> 1;
if( qr <= m ) return query(lch, ql, qr);
else if( ql > m ) return query(rch, ql, qr);
else {
node a = query(lch, ql, qr), b = query(rch, ql, qr), c;
merge(a, b, c, m); return c;
}
}
}T;
void update(int A, int B, double R) {
d[A] += R;
if( A / 4 == B / 4 ) f[A/4].a[A%4][B%4] += R;
else g[A/4].a[A%4][B%4] += R;
get(A/4, h[A/4]), T.update(1, A/4);
}
void remove(int A, int B) {
if( A / 4 == B / 4 ) update(A, B, -f[A/4].a[A%4][B%4]);
else update(A, B, -g[A/4].a[A%4][B%4]);
}
int N, P, D;
void solve() {
scanf("%d%d%d", &N, &P, &D), K = N, N = (N + 3) / 4;
for(int i=0;i<4*N;i++) d[i] = 0;
for(int i=0;i<N;i++)
for(int j=0;j<4;j++)
for(int k=0;k<4;k++)
f[i].a[j][k] = g[i].a[j][k] = 0;
for(int i=1;i<=P;i++) {
int A, B, R; scanf("%d%d%d", &A, &B, &R);
d[A] += R;
int del = B - (A/4*4);
if( del < 4 ) f[A/4].a[A%4][del] += R;
else g[A/4].a[A%4][del-4] += R;
}
for(int i=0;i<N;i++)
get(i, h[i]);
T.build(1, 0, N - 1);
for(int i=1;i<=D;i++) {
int op; scanf("%d", &op);
if( op == 1 ) {
int X, Y, Z; scanf("%d%d%d", &X, &Y, &Z);
update(X, Y, Z);
}
else if( op == 2 ) {
int X, Y; scanf("%d%d", &X, &Y);
remove(X, Y);
}
else {
int X, Y; scanf("%d%d", &X, &Y);
if( X / 4 <= Y / 4 ) {
node p = T.query(1, X / 4, Y / 4);
double ans = 0;
for(int i=0;i<4;i++)
ans += p.a[X%4][i] * h[Y/4].a[i][Y%4];
printf(" %.6f", ans);
}
else printf(" %.6f", 0.0);
}
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
int t; scanf("%d", &t);
for(int i=1;i<=t;i++)
printf("Case #%d:", i), solve(), puts("");
}
/*
5
8 0 10
1 0 1 1
1 1 2 1
1 2 3 1
3 0 3
1 0 4 1
3 0 3
1 0 3 1
3 0 3
2 1 2
3 0 3
4 4 10
0 1 1
1 0 1
1 2 1
0 3 1
3 0 2
2 0 1
1 0 1 2
3 0 2
2 0 1
1 0 1 3
3 0 2
2 0 1
1 0 1 4
3 0 2
8 7 5
0 1 1
1 2 1
2 3 1
0 4 1
1 5 1
2 6 1
3 7 1
3 0 5
3 0 7
1 3 0 1
3 0 5
3 0 7
8 4 10
4 5 1
5 6 1
6 7 1
7 4 1
1 0 4 1
1 0 1 4
3 0 7
1 1 6 1
3 0 7
1 1 2 1
1 2 3 1
3 0 7
1 2 0 1
3 0 7
12 5 7
0 4 1
4 8 1
0 1 1
1 2 1
2 3 1
3 0 8
1 1 4 1
3 0 8
1 2 4 1
3 0 8
1 3 4 1
3 0 8
*/
@details@
做题心路历程:
“woc 这是什么恶心题,算了思路挺简单的,先写再说”
“woc 怎么过不了样例,woc 我题给读错了,它不能往前面那个块跑。没事儿反正也是往简单的方向改”
“woc 怎么卡在第二个数据上了,woc 它竟然 WA 了!怎么办该不会是精度问题吧”
“(去偷了一份正确代码,生成了一点大数据)!怎么会有 nan 这种东西,看来得调试了”
“woc 它高斯消元竟然把一行给消没了?!难道。。。”
然后就发现了问题所在。
@gym - 100591D@ Fox Rocks的更多相关文章
- SDOI2012 走迷宫
走迷宫 Morenan被困在了一个迷宫里.迷宫可以视为N个点M条边的有向图,其中Morenan处于起点S,迷宫的终点设为T.可惜的是,Morenan非常的脑小,他只会从一个点出发随机沿着一条从该点出发 ...
- UVaLive 6581 && Gym 100299B What does the fox say? (模拟+STL)
题意:给定一些动物的叫声,然后再定某些动物的叫声,让你去除这些叫声后得到的叫声. 析:先存储所有的叫声,然后用map来记录其他的叫声,在输出时再判定一下就好. 代码如下: #pragma commen ...
- Gym 102028C - Supreme Command - [思维题][2018-2019 ACM-ICPC Asia Jiaozuo Regional Contest Problem C]
题目链接:https://codeforces.com/gym/102028/problem/C Lewis likes playing chess. Now he has n rooks on th ...
- ACM: Gym 101047M Removing coins in Kem Kadrãn - 暴力
Gym 101047M Removing coins in Kem Kadrãn Time Limit:2000MS Memory Limit:65536KB 64bit IO Fo ...
- ACM: Gym 101047K Training with Phuket's larvae - 思维题
Gym 101047K Training with Phuket's larvae Time Limit:2000MS Memory Limit:65536KB 64bit IO F ...
- ACM: Gym 101047E Escape from Ayutthaya - BFS
Gym 101047E Escape from Ayutthaya Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I6 ...
- ACM: Gym 101047B Renzo and the palindromic decoration - 手速题
Gym 101047B Renzo and the palindromic decoration Time Limit:2000MS Memory Limit:65536KB 64 ...
- [DFNews] Fire-Eye与Fox IT联合推出Cryptolocker解锁网站
Cryptolocker是臭名昭著的勒索程序,使用AES加密后密钥回传,用户除了缴纳赎金之外基本无法解密数据. 近日,知名安全公司Fire-Eye与Fox IT联合推出了针对该勒索程序的解锁网站 ht ...
- 在线教学、视频会议 Webus Fox(1)文本、语音、视频聊天及电子白板基本用法
Webus Fox是基于网页的在线教学.视频会议软件,不用安装,直接使用.它提供文本.语音.视频聊天,文件共享.电子白板等功能. 1. 登录 访问 http://flash.webus.cn/#,用自 ...
随机推荐
- tp入门
其中可以配置隐藏看入口文件 和默认读取路径 <?php namespace app\admin\controller; //生命控制器 class Index { public function ...
- 在Cent OS云服务器上部署基于TP5后端代码踩坑记录_艾孜尔江撰
推荐使用镜像安装Cent OS系统,或者在纯净安装完成之后在完成Apache+MySQL+PHP的时候不要每个单独安装,因为这样会出一些三者之间版本不配的问题,网上各种说法都有,查起来也非常困难,版本 ...
- 跳出初学MySQL知识的原理整理(一)
一.基础架构 MySQL 可以分为 Server 层和存储引擎层两部分. Server 层包括连接器.查询缓存.分析器.优化器.执行器等,所有跨存储引擎 的功能都在这一层实现,比如存储过程.触发器.视 ...
- 一、CentOS6.8安装MySQL5.6
一.官网下载rpm安装包 https://dev.mysql.com/downloads/ 版本选中如图中红色框 二.卸载旧mysql 1.检查是否安装有mysql rpm -qa | grep -i ...
- HTTP——无状态协议理解
无状态服务器是指一种把每个请求作为与之前任何请求都无关的独立的事务的服务器. HTTP是一个属于应用层的面向对象的协议 ------未完待续
- Android_存储之scoped storage&媒体文件
Scoped storage 文件存储介绍了内部存储和外部存储相关的内容.因为外部存储容易读写,所以在手机中经常看到很多“乱七八糟”的文件或文件夹,这些就是应用肆意创建的. Android Q(10) ...
- Sniffer截包工具的使用
Sniffer软件的安装 sniffer需要在xp或者win2003环境下才能正常运行,如果没有这两个系统,可以安装虚拟机,在虚拟机上使用sniffer.如果没有这两个系统就会出现找不到网卡或者打不开 ...
- MP4视频流base64数据转成Blob对象
网上一大堆对图片base64转Blob.File的方法 很少有视频mp4转的,可能是因为原理相同的原因吧!但在项目中针对视频流base64转Blob对象时,花了好长时间才成功,特专门记录一下! APP ...
- 一篇文章,全面掌握Git
版本控制 版本控制就是记录项目文件的历史变化.它为我们查阅日志,回退,协作等方面提供了有力的帮助. 版本控制一般分为集中化版本控制和分布式版本控制. 集中化主要的版本数据都保存服务端. 分布式版本数据 ...
- PHP生成指定范围的日期
/** * 生成指定范围的日期 * * @param $string $startDate 开始日期 2020-01-01 * @param $string $endDate 结束日期 2020-01 ...