*题解:P2151 [SDOI2009] HH 去散步

题目链接

解析

考虑没有不能立刻往回走的限制怎么做。

\(f_{i,j}\) 表示长度为 \(i\) 的从 \(A\)\(j\) 的路径条数。则有:

\[f_{i,j} = \sum_{k=1}^{N} f_{i - 1,k} \cdot e_{k,j} \]

其中 \(e_{k,j}\) 表示连接 \(k\)\(j\) 的边数。

\(t\) 很大,矩阵加速即可。

对于限制,我们有个 trick 叫点边互化。既然对边有限制,那就把边放到状态里。把无向边拆成两条有向边,重新设 \(f_{i,j}\) 表示长度为 \(i\) 的从 \(A\) 经过边 \(j\) 走到边 \(j\) 终点的方案数。则有:

\[f_{i,j} = \sum_{k\in S_j}f_{i - 1,k} \]

其中 \(S_j\) 为终点为边 \(j\) 起点的边的编号组成的集合。

同样,矩阵加速即可。

时间复杂度 \(O(M^3 \log t)\)

代码

我的实现需要从虚空中拉一条边指向 \(A\),用于初始矩阵。

/*
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 50 + 5,M = 60 + 5,P = 2000000,mod = 45989;
vector<int> to[N];
int u[M * 2],v[M * 2];
struct Mtx{
	int row,col;
	int m[M * 2][M * 2];
	Mtx(int r,int c) : row(r),col(c) {
		for(int i=1;i<=row;i++){
			for(int j=1;j<=col;j++){
				m[i][j] = 0;
			}
		}
	}
	void I(){
		for(int i=1;i<=row;i++){
			m[i][i] = 1;
		}
	}
	friend Mtx operator * (Mtx a,Mtx b){
		Mtx c(a.row,b.col);
		for(int i=1;i<=a.row;i++){
			for(int j=1;j<=b.col;j++){
				for(int k=1;k<=a.col;k++){
					c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j]) % mod;
				}
			}
		}
		return c;
	}
	void print(){
		for(int i=1;i<=row;i++){
			for(int j=1;j<=col;j++){
				cout<<m[i][j]<<" \n"[j==col];
			}
		}
		cout<<"_______________________________\n";
	}
};
Mtx qmi(Mtx a,int b){
	Mtx res(a.row,a.col);
	res.I();
	while(b){
		if(b & 1) res = res * a;
		b >>= 1;
		a = a * a;
	}
	return res;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,m,t,A,B;
	cin>>n>>m>>t>>A>>B;
	for(int i=1;i<=m;i++){
		cin>>u[i]>>v[i];
		u[m + i] = v[i];
		v[m + i] = u[i];
		to[v[i]].push_back(i);
		to[u[i]].push_back(m + i);
	}
	to[A].push_back(2 * m + 1);
	Mtx mt(m * 2 + 1,m * 2 + 1);
	for(int i=1;i<=m * 2;i++){
		for(int j : to[u[i]]){
			mt.m[i][j] = 1;
		}
		if(i <= m) mt.m[i][i + m] = 0;
		else mt.m[i][i - m] = 0;
	}
	Mtx ori(2 * m + 1,1);
	ori.m[2 * m + 1][1] = 1;
	Mtx resm = qmi(mt,t) * ori;
	int res = 0;
	for(int j : to[B]){
		res = (res + resm.m[j][1]) % mod;
	}
	cout<<res;
	return 0;
}
posted @ 2026-06-01 23:24  yutar  阅读(9)  评论(0)    收藏  举报