有向图

给你一个 \(n+m\) 的有向图,边上带 \(\in (0,1]\) 的边权。

保证:

  • \(\forall x,y \in [1,n]\)\(x\)\(y\) 之间存在一对反向边。
  • \(\forall x\in [1,n],y\in[n+1,n+m]\),存在一条从 \(x\)\(y\) 的单向边。
  • \(\forall x,y\in [n+1,n+m]\)\(x\)\(y\) 之间没有任何边。

从时刻 \(0\) 开始,若当前在 \(x\),下一个时刻走到 \(y\) 的概率是 \(x\) 指向 \(y\) 的边的边权。保证一个点的出边边权之和为 \(1\)

从点 \(1\) 开始游走,求无穷多步之后停在每个点的概率。


\(x_i\) 表示所有以 \(i\) 为结尾的路径出现的概率之和。

那么不难有以下转移:

\[x_i=\sum_j p_{j,i} x_j \]

显然概率之和为 \(1\),所以还有额外的一条:

\[\sum_i x_i=1 \]

但是这种情况下整个方程组不一定有解,怎么办呢。

我们可以将后 \(m\) 个点全部向 \(1\) 连边权为 \(1\) 的单向边。

这相当于我们经过了一次后 \(m\) 个点之一后重新开始一轮。

不难发现这样不影响最后的答案。

同时我们会发现,这种情况下,所有点的出边边权之和都为 \(1\)

那么图的邻接矩阵 \(G\) 就是一个行随机矩阵,\(1\) 必然是 \(G\) 的特征值。

所以如果我们考虑这个等价的方程:

\[G\textbf x=\textbf x \]

因此必然存在解。

解出来后,将后 \(m\) 个点的答案归一化后输出即可。


#include <algorithm>
#include <iostream>
#include <vector>

const int O = 1e9 + 7, N = 501;
typedef long long i64;

i64 O_inv(i64 a, int O = O) {
	i64 res = 1, base = a, power = O - 2;
	while (power) {
		if (power & 1) res = res * base % O;
		base = base * base % O;
		power >>= 1;
	}
	return res;
}

const i64 i4 = O_inv(10000);

std::vector<i64> solveLinearSystem(std::vector<std::vector<i64>> A, std::vector<i64> B) {
	int n = A.size(), m = A[0].size();
	
	std::vector<std::vector<i64>> aug(n, std::vector<i64>(m + 1));
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++)
			aug[i][j] = A[i][j];
		aug[i][m] = B[i];
	}
	
	std::vector<int> where(m, -1);
	int row = 0;
	for (int col = 0; col < m && row < n; col++) {
		int pivot = -1;
		for (int i = row; i < n; i++) {
			if (aug[i][col] != 0) {
				pivot = i;
				break;
			}
		}
		
		std::swap(aug[row], aug[pivot]);
		where[col] = row;
		
		int inv = O_inv(aug[row][col], O);
		for (int j = col; j <= m; j++) {
			aug[row][j] = (1LL * aug[row][j] * inv) % O;
		}
		
		for (int i = 0; i < n; i++) {
			if (i != row && aug[i][col]) {
				int factor = aug[i][col];
				for (int j = col; j <= m; j++)
					aug[i][j] = (aug[i][j] + O - 1LL * factor * aug[row][j] %O) % O;
			}
		}
		
		row++;
	}
	
	std::vector<i64> x(m, 0);
	for (int j = 0; j < m; j++) {
		if (where[j] != -1) {
			x[j] = aug[where[j]][m];
		}
	}
	
	return x;
}

int n, m;

i64 p[N][N];

inline void solve() {
	for(int i = 0; i < n; ++i)
		for(int j = 0; j < n+m; ++j)
			std::cin >> p[i][j], p[i][j] = p[i][j] * i4 %O;
	
	std::vector<i64> b(n+m, 0);
	std::vector<std::vector<i64>> a(n+m+1, b);
	
	for(int j = n; j < n+m; ++j)
		a[0][j] = 1;
	for(int i = 0; i < n+m; ++i) {
		for(int j = 0; j < n; ++j)
			a[i][j] = p[j][i];
		a[i][i] -= 1;
	}
	
	for(int i = 0; i < n+m; ++i)
		a[n+m][i] = 1;
	b.push_back(1);
	
	auto res = solveLinearSystem(a, b);
	
	i64 sum = 0;
	for(int i = n; i < n+m; ++i)
		sum += (res[i] %= O);
	
	sum %= O, sum = O_inv(sum);
	for(int i = n; i < n+m; ++i)
		std::cout << res[i] * sum %O << " ";
	std::cout << "\n";
}

int main() {
	while(std::cin >> n >> m) {
		solve();
	}
}
posted @ 2025-09-16 15:17  CuteNess  阅读(7)  评论(0)    收藏  举报