Codeforces Round #487 (Div. 2) E. A Trance of Nightfall (矩阵优化)
题意
有一个平面 , 给你 \(n\) 个点构成一个点集 \(S\) , 一开始可以选择一个平面上任意点 \(P\) .
存在一种操作 :
1 选择一条至少 通过 \(S\) 中任意两个点以及 \(P\) 点 的直线, 然后可以在这条直线上等概率选择一个在 \(S\) 中的点 \(v\) .
如果有多条直线 , 那么等概率选择任意一条 . (可以原地不动)
2 选择了这个点 \(v\) 后 , 将 \(P\) 移动到这个点 .
也就是只有第一次可以自己随机选择点 , 后面等概率随机移动 \(P\) 点
有 \(q\) 次询问 .
每次有两个参数 \(t_i, m_i\) , 询问 在 \(m_i\) 次操作后 , 停留在第 \(t_i\) 个点的最大概率 .
\((n \le 200, q \le 200, m_i \le 10^4)\)
题解
考试的时候只差一点点就想出来了 ... 询问的时候每次复杂度多了一个 \(O(n)\) TAT
如果第一次选的不是存在于原图中线上的点 , 那么概率是 \(0\) 就没有用啦 .
所以第一次就是直接选择一条直线 , 然后去用 dp 算答案啦 qwq
令 \(dp_{i,j}\) 为第 \(i\) 次到 \(j\) 号点的概率 , 我们每次询问只要回答对于每条线 最后答案就是 \(\displaystyle \max_{line} dp_{t_i,m_i}\) .
转移的话 我们只要预处理出过点 \(P\) 的线 , 以及线上的点就行了 (用叉积判断三点共线就行了)
然后 \(P\) 到这些点的转移系数就直接算就行了 qwq
( 令过 \(P\) 的直线数为 \(s_1\) , 然后 \(Pv\) 直线上的点数为 \(s_2\) . 选 \(v\) 概率为 \(\displaystyle \frac{1}{s_1 \times s_2}\) )
暴力实现这个过程的复杂度就是 \(O(qn^2m_i)\) 无法承受 , 就算是预处理也需要 \(O(n^2m_i)\) 的空间和时间 .
我们不难发现 , 对于这种 常系数齐次线性递推式 常常有一个套路 矩阵乘法优化 qwq .
我们对于那些系数构造出矩阵 , 每次操作相当于一次矩阵乘法 .
也就是说 对于矩阵中的 \((i,j)\) 这个位置的值 代表 \(i \to j\) 的概率 .
然后 用套路 开始预处理 \(2^i\) 次方的转移矩阵就行了 . 每次查询的时候考虑用这些矩阵来转移出最后的答案 .
令 \(f_i\) 为 \(i\) 到当前目标 \(m\) 的概率 . 我们就可以考虑用这个矩阵转移出 \(t_i\) 步后的概率 .
把 \(t_i\) 二进制分解后 第 \(j\) 位如果为 \(1\) 那么我们就可以用这个矩阵来转移啦 .
转移就是 \(\displaystyle f_i = \sum_{j=1}^{n} coef[i][j] ~ f_j\) 就是 \(i \to m\) 相当于 \(\forall j, ~ i \to j \to m\) .
注意 \(t_i = 1\) 的时候要特判一下 \(f_i\) .
然后每次枚举一条边 , 算出线上所有点 \(p_i\) 的和 除以选择线上的点数 , 最后取一个 \(\max\) 就行了 .
最后分析下时间复杂度 qwq
线上所有点个数之和为 \(O(n^2)\) , 预处理是 \(O(n^3 \log t_i)\) 的 , 回答单个询问做的转移次数是 \(O(n^2 \log t_i)\) 的 .
所以时间复杂度就是 \(O(n^3 \log t_i+qn^2 \log t_i)\) . 卡卡常只要 \(202ms\) 就跑完啦 ~
代码
#include <bits/stdc++.h>zjp
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ':' << x << endl
#define pb push_back
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
    int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
    for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
    return x * fh;
}
void File() {
#ifdef zjp_shadow
	freopen ("E.in", "r", stdin);
	freopen ("E.out", "w", stdout);
#endif
}
const int N = 210;
const double eps = 1e-8;
int n, m;
struct Matrix { double a[N][N]; Matrix() { Set(a, 0); } } ;
inline Matrix operator * (Matrix a, Matrix b) {
	Matrix res;
	For (i, 1, n) For (k, 1, n) if (a.a[i][k] > eps)
		For (j, 1, n) res.a[i][j] += a.a[i][k] * b.a[k][j];
	return res;
}
Matrix Bas[21];
int cnt = 0; vector<int> lis[N * N]; bool InLine[N][N];
struct Point { int x, y; } lt[N];
inline bool Collinear (Point a, Point b, Point c) {
	return (a.y - b.y) * (b.x - c.x) == (b.y - c.y) * (a.x - b.x);
}
int tot[N]; double coef[N][N];
void Init() {
	For (i, 1, n - 1) {
		For (j, i + 1, n) if (!InLine[i][j]) {
			lis[++ cnt].pb(i); lis[cnt].pb(j);
			For (k, j + 1, n)
				if (Collinear(lt[i], lt[j], lt[k])) lis[cnt].pb(k);
			For (k, 0, lis[cnt].size() - 1) For (l, 0, lis[cnt].size() - 1)
				InLine[lis[cnt][k]][lis[cnt][l]] = true;
		}
	}
	For (i, 1, cnt)
		for (int ver : lis[i]) ++ tot[ver];
	For (i, 1, cnt) {
		int Size = (int)lis[i].size();
		for (int beg : lis[i]) for (int ver : lis[i])
			coef[beg][ver] += 1.0 / tot[beg] / Size;
	}
	For (i, 1, n) For (j, 1, n) Bas[0].a[i][j] = coef[i][j];
	int cur = 1;
	for (int i = 1; ; ++ i) {
		if ((cur <<= 1) > 10000) break;
		Bas[i] = Bas[i - 1] * Bas[i - 1];
	}
}
double prob[N], tmp[N];
double Answer(int times, int ver) {
	if (!(-- times)) {
		For (i, 1, n) prob[i] = (i == ver) ? 1 : 0;
	}
	else {
		bool fir = true;
		For (p, 0, 18)
			if ((times >> p) & 1) {
				if (fir) { fir = false; For (i, 1, n) prob[i] = Bas[p].a[i][ver]; }
				else {
					For (i, 1, n) {
						double cur = .0; For (j, 1, n) cur += Bas[p].a[i][j] * prob[j]; tmp[i] = cur;
					}
					swap(prob, tmp);
				}
			}
	}
	double res = .0;
	For (i, 1, cnt) {
		double sum = .0;
		for (int v : lis[i])
			sum += prob[v] / (double)lis[i].size();
		res = max(res, sum);
	}
	return res;
}
int main () {
	File();
	n = read();
	For (i, 1, n)
		lt[i] = (Point) {read(), read()};
	Init();
	m = read();
	For (i, 1, m) {
		int ver = read(), times = read();
		printf ("%.10lf\n", Answer(times, ver));
	}
	return 0;
}
Codeforces Round #487 (Div. 2) E. A Trance of Nightfall (矩阵优化)的更多相关文章
- Codeforces Round #487 (Div. 2)  C - A Mist of Florescence
		C - A Mist of Florescence 把50*50的矩形拆成4块 #include<bits/stdc++.h> using namespace std; ],b[]; ][ ... 
- Codeforces Round #487 (Div. 2) 跌分有感
		又掉分了 这次的笑话多了. 首先,由于CF昨天的比赛太早了,忘记了有个ER,比赛开始半个小时才发现. 于是只能今天了. 嗯哈. 今天这场也算挺早的. 嗯嗯,首先打开A题. 草草看了一遍题意,以为不是自 ... 
- C. A Mist of Florescence ----- Codeforces Round #487 (Div. 2)
		C. A Mist of Florescence time limit per test 1 second memory limit per test 256 megabytes input stan ... 
- Codeforces Round #487 (Div. 2)
		A. A Blend of Springtime(暴力/模拟) 题目大意 给出$n$个花,每个点都有自己的颜色,问是否存在连续大于等于三个花颜色均不相同 sol 直接模拟判断即可 #include&l ... 
- Codeforces Round #487 (Div. 2)   A Mist of Florescence (暴力构造)
		C. A Mist of Florescence time limit per test 1 second memory limit per test 256 megabytes input stan ... 
- code forces Codeforces Round #487 (Div. 2)  C
		C. A Mist of Florescence time limit per test 1 second memory limit per test 256 megabytes input stan ... 
- Codeforces Round #487 (Div. 2) C. A Mist of Florescence 构造
		题意: 让你构造一个 n∗mn*mn∗m 矩阵,这个矩阵由 444 种字符填充构成,给定 444 个整数,即矩阵中每种字符构成的联通块个数,n,mn,mn,m 需要你自己定,但是不能超过505050. ... 
- Codeforces Round #257(Div. 2) B. Jzzhu and Sequences(矩阵高速幂)
		题目链接:http://codeforces.com/problemset/problem/450/B B. Jzzhu and Sequences time limit per test 1 sec ... 
- Codeforces Round #207 (Div. 1)  D - Bags and Coins  构造 + bitset优化dp + 分段查找优化空间
		D - Bags and Coins 思路:我们可以这样构造,最大的那个肯定是作为以一个树根,所以我们只要找到一个序列a1 + a2 + a3 .... + ak 并且ak为 所有点中最大的那个,那么 ... 
随机推荐
- win10 + VS2010 + OpenCV2.4.10重编译OpenCV开发环境搭建
			win10 + VS2010 + OpenCV2.4.10重编译OpenCV开发环境搭建 重编译的优点:能够调试的时候看OpenCV的源码. 重编译要得到的东西:Debug版本号和Release版本号 ... 
- Trusted Block Chain Summit(2018.10.09)
			时间:2018.10.09地点:北京金隅喜来登大酒店 
- spring boot配置统一异常处理
			基于@ControllerAdvice的统一异常处理 >.这里ServerException是我自定义的异常,和普通Exception分开处理 >.这里的RequestResult是我自定 ... 
- 在python中使用正则表达式(一)
			在python中通过内置的re库来使用正则表达式,它提供了所有正则表达式的功能. 一.写在前面:关于转义的问题 正则表达式中用“\”表示转义,而python中也用“\”表示转义,当遇到特殊字符需要转义 ... 
- RabbitMQ TroubleShooting
			RabbitMQ是一款优秀的消息队列中间件,提供了稳定.监控完善的产品,但是软件就会有bug.为了前进路径可以畅通,我们必须了解出现的一些故障的快速处理方式,毕竟在生产环境,时间就是生命,尽快的处理是 ... 
- SQL中not in 和not exists
			在SQL中倒是经常会用到子查询,而说到子查询,一般用的是in而不是exists,先不谈效率问题,就先说说会遇到哪些问题. 用到in当取反的时候,肯定先想到的就是not in.但是在使用not in的时 ... 
- 理解Vue 2.5的Diff算法
			DOM"天生就慢",所以前端各大框架都提供了对DOM操作进行优化的办法,Angular中的是脏值检查,React首先提出了Virtual Dom,Vue2.0也加入了Virtual ... 
- Wannafly挑战赛25 A.因子
			传送门 [https://www.nowcoder.com/acm/contest/197/A] 题意 给你n,m,让你求n!里有多少个m 分析 看这个你就懂了 [https://blog.csdn. ... 
- Week 7 迭代总结
			写在前面: 本次我为团队博客写了一篇总结,深刻总结了我们组发生的问题以及将来要做的事情.有兴趣请移步http://www.cnblogs.com/Buaa-software Week 7 Alpha轮 ... 
- BugPhobia开发篇章:Beta阶段第IX次Scrum Meeting
			0x01 :Scrum Meeting基本摘要 Beta阶段第九次Scrum Meeting 敏捷开发起始时间 2015/12/25 00:00 A.M. 敏捷开发终止时间 2015/12/28 23 ... 
