P5789 [TJOI2017]可乐 矩阵乘法

P5789 [TJOI2017]可乐 矩阵乘法

题目链接

​ 说实话这个自爆的问题难住我了, 其他的都还挺好想的.

​ 操作一 : 走到相邻的点, 如果(x)可以走到(y), 那么我们另(g[x][y] = g[y][x] = 1), 表示这两个点之间可以相互走.

​ 操作二 : 停在原地 , 相当于自己有一条到自己的边.

​ 操作三 : 自爆 , 我们可以假设有一个0点, 然后所有点都可以向0点连边, 而0点不能向外连边. 这个和自爆的性质是一样的.

其实也蛮水的, TESknight零秒就切出来了%%%

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 105, mod = 2017;
int n, m, k, ans_;
struct mat {
	int v[N][N];
	void init() { for(int i = 0;i <= n; i++) for(int j = 0;j <= n; j++) v[i][j] = 0; }
	friend mat operator * (const mat &a, const mat &b) {
		mat c; c.init();
		for(int k = 0;k <= n; k++)
			for(int i = 0;i <= n; i++)
				if(a.v[i][k])
				for(int j = 0;j <= n; j++)
					if(b.v[k][j]) c.v[i][j] = (c.v[i][j] + 1ll * a.v[i][k] * b.v[k][j] % mod) % mod; 
		return c;
	}
} ans, turn;

mat ksm(mat x, int y) {
	mat res; res.init(); for(int i = 0;i <= n; i++) res.v[i][i] = 1;
	while(y) { if(y & 1) res = res * x; x = x * x; y >>= 1; }
	return res;
}

int main() {
	
	n = read(); m = read();
	for(int i = 1, x, y;i <= m; i++) x = read(), y = read(), turn.v[x][y] = turn.v[y][x] = 1;
	for(int i = 0;i <= n; i++) turn.v[i][0] = turn.v[i][i] = 1;
	k = read(); ans = ksm(turn, k); 
	for(int i = 0;i <= n; i++) ans_ = (ans_ + ans.v[1][i]) % mod;
	printf("%d", ans_);

	return 0;
}
原文地址:https://www.cnblogs.com/czhui666/p/14014614.html