zoukankan      html  css  js  c++  java
  • BZOJ4386 [POI2015]Wycieczki 矩阵+倍增

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=4386

    题解

    一眼就可以看出来是邻接矩阵快速幂。

    可是这里的边权不为 (1)。不过可以发现,边权最多为 (3)。但是边的数量很多,不适合拆边,那就拆点吧。对于一条 (x o y) 的边,就建立一个 (x_0 o y_{w - 1}) 的边,(w) 为边权。

    然后就建立矩阵就可以了。因为我们需要统计第 (i) 步之前一共有多少路径,所以可以新建一个节点,每个点向这个点连一条有向边,这个点自己再来一个自环。

    然后预处理 (B_i) 为走了 (2^i) 步的矩阵,直接倍增出来答案就可以了。


    下面是代码,矩阵乘法的复杂度为 (O(n^3)),一共倍增 (O(log k)) 次,因此总的时间复杂度为 (O(n^3log k))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I>
    inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 40 * 3 + 7;
    
    int n, m;
    ll k;
    
    struct Matrix {
    	ll a[N][N];
    	inline Matrix() { memset(a, 0, sizeof(a)); }
    	
    	inline Matrix operator * (const Matrix &b) {
    		Matrix c;
    		for (int k = 0; k <= n; ++k)
    			for (int i = 0; i <= n; ++i)
    				for (int j = 0; j <= n; ++j)
    					c.a[i][j] += a[i][k] * b.a[k][j];
    		return c;
    	}
    	
    	inline void print() const {
    		for (int i = 0; i <= n; ++i) {
    			for (int j = 0; j <= n; ++j) dbg("%lld ", a[i][j]);
    			dbg("
    ");
    		}
    	}
    } A, B[N];
    
    inline bool isfull(const Matrix &a) {
    	ll cnt = 0;
    	for (int i = 1; i <= n / 3; ++i) {
    		cnt += a.a[i][0] - 1;
    		if (cnt >= k) return 1;
    	}
    	return 0;
    }
    
    inline void work() {
    	n = n * 3, B[0] = A;
    	int lim = 0;
    	for (int i = 1; i <= 70; ++i) {
    		B[i] = B[i - 1] * B[i - 1];
    		++lim;
    		if (isfull(B[i])) break;
    	}
    	if (!isfull(B[lim--])) {
    		puts("-1");
    		return;
    	}
    	memset(A.a, 0, sizeof(A.a));
    	for (int i = 0; i <= n; ++i) A.a[i][i] = 1;
    	ll ans = 0;
    	for (int i = lim; ~i; --i) {
    		const Matrix &tmp = A * B[i];
    		if (!isfull(tmp)) A = tmp, ans += 1ll << i;
    	}
    	printf("%lld
    ", ans);
    }
    
    inline void init() {
    	read(n), read(m), read(k);
    	for (int i = 1; i <= m; ++i) {
    		int x, y, z;
    		read(x), read(y), read(z);
    		if (z == 1) ++A.a[x][y];
    		if (z == 2) ++A.a[x][y + n];
    		if (z == 3) ++A.a[x][y + n * 2];
    	}
    	for (int i = 1; i <= n; ++i) A.a[i][0] = A.a[i + n][i] = A.a[i + n * 2][i + n] = 1;
    	A.a[0][0] = 1;
    }
    
    int main() {
    #ifdef hzhkk 
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    python全栈-Day 4
    5个步骤实现软件质量的快速提升
    如何选择正确的静态应用安全测试(SAST)解决方案?
    安全工具箱必备技术之静态分析安全测试(SAST)
    精彩回顾:2020年自动化软件测试质量峰会
    怎样才能明智地利用代码覆盖率来最大限度地提高测试效率?
    软件开发你不可不知的那些事:如何有效减轻风险和质量债务?
    敏捷开发中不为人知的小秘密,你是否深有同感?
    当AI遇上API测试 — 敏捷开发已迎来革新时代!
    面对行业分析家和敏捷专家都认可的API测试,我们为什么会望而却步?
  • 原文地址:https://www.cnblogs.com/hankeke/p/BZOJ4386.html
Copyright © 2011-2022 走看看