bzoj1875 边点互换+矩乘
https://www.lydsy.com/JudgeOnline/problem.php?id=1875
题意 HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但
是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每
天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都
是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径
开始没有看到不能走回头路的条件,以为是道人尽皆知傻逼矩阵快速幂,WA了好几发后才发现这个奇形怪状的条件。
既然不能走回头路,我们就不能用点构造矩阵了,考虑直接用边来构造矩阵,表示边与边之间到达的关系。
dp[i][j]表示边i通过k次操作到达边j的数目。
我们建立两个虚点,一个x指向所有起点为S的边,一个y被所有终点为T的边指向,最终x需要经过K + 1条边到达y的数目即为答案
构造矩阵即可。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 125; const int INF = 0x3f3f3f3f; const int mod = 45989; int N,M,tmp,K,tot; int S,T; struct Mat{ LL a[maxn][maxn]; void init(){ Mem(a,0); } }base; struct Edge{ int u,v; Edge(int u = 0,int v = 0):u(u),v(v) {} }edge[maxn]; Mat operator * (Mat a,Mat b){ Mat ans; ans.init(); for(int i = 0 ; i <= tot ; i ++){ for(int j = 0 ; j <= tot; j ++){ for(int k = 0; k <= tot; k ++){ ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod; } } } return ans; } Mat operator ^ (Mat a,int b){ Mat x,y = a; x.init(); For(i,0,tot) x.a[i][i] = 1; while(b){ if(b & 1) x = x * y; b >>= 1; y = y * y; } return x; } void solve(){ base = base ^ (K + 1); printf("%lld",base.a[0][1]); } int main() { scanf("%d%d%d%d%d",&N,&M,&K,&S,&T); base.init(); tot = 2; For(i,1,M){ int u,v; Sca2(u,v); edge[tot++] = Edge(u,v); edge[tot++] = Edge(v,u); } tot--; For(i,2,tot){ if(edge[i].u == S) base.a[0][i] = 1; if(edge[i].v == T) base.a[i][1] = 1; For(j,2,tot){ if(edge[i].v == edge[j].u && (i ^ j ) != 1) base.a[i][j] = 1; } } solve(); #ifdef VSCode system("pause"); #endif return 0; }