计数问题也许可以转化为矩阵乘法形式
比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可
故
矩阵乘法计数
对于计数问题,若可以将 \(n\) 个点表示成 \(n \times n\) 的矩阵,并且可以保证中途转移对象不会变化,即可用矩阵乘法计数
至于该题
那么考虑该题,加入了不能重复在一条边上走的限制,那么最简单的思想就是拆点,并且让改点屏蔽掉当前方向,但是如果考虑边,一条无向边可以拆成两条有向边,那拆出来的就比点少很多了,故考虑点边转化
那么只要在起始点加一条超级源边,同样矩阵乘法即可统计答案
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define MOD 45989
using namespace std;
typedef long long LL;
const int MAXN = 50 + 10;
const int MAXM = 120 + 10;
struct LinkedForwardStar {
int to;
int next;
} ;
LinkedForwardStar Link[MAXM];
int Head[MAXN]= {0};
int size = 1;
void Insert (int u, int v) {
Link[++ size].to = v;
Link[size].next = Head[u];
Head[u] = size;
}
int N, M, K;
int st, ed;
struct Matrix {
LL a[MAXM][MAXM];
void init () {
for (int i = 1; i <= size; i ++)
for (int j = 1; j <= size; j ++)
a[i][j] = 0;
}
Matrix operator * (const Matrix& p) const {
Matrix newmat;
newmat.init ();
for (int i = 1; i <= size; i ++)
for (int j = 1; j <= size; j ++)
for (int k = 1; k <= size; k ++)
newmat.a[i][j] = (newmat.a[i][j] + a[i][k] * p.a[k][j] % MOD) % MOD;
return newmat;
}
} ;
Matrix mats, bem;
LL power (int p) {
while (p) {
if (p & 1)
mats = mats * bem;
bem = bem * bem;
p >>= 1;
}
LL ans = 0;
for (int i = Head[ed]; i; i = Link[i].next)
ans = (ans + mats.a[1][i ^ 1]) % MOD;
return ans;
}
int getnum () {
int num = 0;
char ch = getchar ();
while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
return num;
}
int main () {
N = getnum (), M = getnum (), K = getnum (), st = getnum () + 1, ed = getnum () + 1;
for (int i = 1; i <= M; i ++) {
int u = getnum () + 1, v = getnum () + 1;
Insert (u, v), Insert (v, u);
}
for (int i = Head[st]; i; i = Link[i].next)
bem.a[1][i] = 1;
for (int i = 2; i <= size; i ++) {
int v = Link[i].to;
for (int j = Head[v]; j; j = Link[j].next) {
if ((j ^ 1) == i)
continue;
bem.a[i][j] = 1;
}
}
for (int i = 1; i <= size; i ++)
mats.a[i][i] = 1;
LL ans = power (K);
cout << ans << endl;
return 0;
}
/*
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
*/