1. 程式人生 > >P2151 [SDOI2009]HH去散步 矩陣快速冪模板

P2151 [SDOI2009]HH去散步 矩陣快速冪模板

P2151 [SDOI2009]HH去散步

題目描述

HH有個一成不變的習慣,喜歡飯後百步走。所謂百步走,就是散步,就是在一定的時間 內,走過一定的距離。 但是同時HH又是個喜歡變化的人,所以他不會立刻沿著剛剛走來的路走回。 又因為HH是個喜歡變化的人,所以他每天走過的路徑都不完全一樣,他想知道他究竟有多 少種散步的方法。

現在給你學校的地圖(假設每條路的長度都是一樣的都是1),問長度為t,從給定地 點A走到給定地點B共有多少條符合條件的路徑

輸入輸出格式

輸入格式:

 

第一行:五個整數N,M,t,A,B。其中N表示學校裡的路口的個數,M表示學校裡的 路的條數,t表示HH想要散步的距離,A表示散步的出發點,而B則表示散步的終點。

接下來M行,每行一組Ai,Bi,表示從路口Ai到路口Bi有一條路。資料保證Ai != Bi,但 不保證任意兩個路口之間至多隻有一條路相連線。 路口編號從0到N − 1。 同一行內所有資料均由一個空格隔開,行首行尾沒有多餘空格。沒有多餘空行。 答案模45989。

 

輸出格式:

 

一行,表示答案。

 

輸入輸出樣例

輸入樣例#1:  複製
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
輸出樣例#1:  複製
4

說明

對於30%的資料,N ≤ 4,M ≤ 10,t ≤ 10。

對於100%的資料,N ≤ 50,M ≤ 60,t ≤ 2^30,0 ≤ A,B

 

題解:

按邊構造矩陣快速冪裸題

// luogu-judger-enable-o2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long
const ll mod = 45989;
int n, gu[130], gv[130], c;
struct Mat{
    ll w[
125][125]; void unit(){ for(int i = 1; i <= c; i++) for(int j = 1; j <= c; j++) w[i][j] = (i == j); } void init(){ for(int i = 1; i <= c; i++) for(int j = 1; j <= c; j++) w[i][j] = 0; } void print(){ for(int i = 1; i <= c; i++){ for(int j = 1; j <= c; j++)printf("%lld ", w[i][j]); puts(""); } } }rec, p; Mat operator * (const Mat &s, const Mat &t){ Mat a; a.init(); for(int i = 1; i <= c; i++) for(int j = 1; j <= c; j++) for(int k = 1; k <= c; k++) a.w[i][j] = (a.w[i][j] + s.w[i][k] * t.w[k][j]) % mod; return a; } Mat ksm(Mat a, int b){ Mat ret; for(ret.unit(); b; b >>= 1, a=a*a) if(b&1) ret=ret*a; return ret; } int main(){ int m, u, v, t, a, b; ll ans = 0; scanf("%d%d%d%d%d", &n, &m, &t, &a, &b); rec.init(); c = m<<1; Mat f; f.init(); for(int i = 1; i <= c; i+=2){ scanf("%d%d", &gu[i], &gv[i]); gu[i+1] = gv[i], gv[i+1] = gu[i]; if(gu[i] == a) f.w[i][1] = 1; if(gu[i+1] == a) f.w[i+1][1] = 1; } if(t == 0) return !printf("%d\n", a != b); for(int i = 1; i <= c; i++) for(int j = 1; j <= c; j++){ if(gv[i] == gu[j] && (i+1)/2 != (j+1)/2) rec.w[j][i] = 1; } //rec.print(); rec = ksm(rec, t-1); //rec.print(); f = rec * f; //f.print(); for(int i = 1; i <= c; i++) if(gv[i] == b) ans = (ans + f.w[i][1]) % mod; printf("%lld\n", ans); }
View Code