1. 程式人生 > >bzoj1875 邊點互換+矩乘

bzoj1875 邊點互換+矩乘

math 快速冪 一個 \n const fine _for 關系 ems

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; }

bzoj1875 邊點互換+矩乘