標籤:bzoj 矩陣乘法 dp 圖論 sdoi 2009
題目大意:給出一張無向圖,求從A到B走k步(不能走回頭路)的方案數。(k <= 2^30)
思路:看到k的範圍就知道是矩陣乘法了。關鍵是不能走回頭路怎麼構造。正常的方法構造點的轉移不能避免這個問題,就用邊來構造。只要保證不經過自己^1的邊就可以保證不走回頭路了。
CODE:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 210#define MO 45989using namespace std; int total = 1; struct Matrix{ int num[MAX][MAX]; Matrix() { memset(num,0,sizeof(num)); } Matrix operator *(const Matrix &a)const { Matrix re; for(int i = 0; i <= total; ++i) for(int j = 0; j <= total; ++j) for(int k = 0; k <= total; ++k) { re.num[i][j] += num[i][k] * a.num[k][j]; re.num[i][j] %= MO; } return re; }}src,ans,temp; int points,edges,t;int S,T;int head[MAX];int next[MAX],aim[MAX]; inline void Add(int x,int y){ next[++total] = head[x]; aim[total] = y; head[x] = total;} int stack[MAX],top; int main(){ cin >> points >> edges >> t >> S >> T; ++S,++T; for(int x,y,i = 1; i <= edges; ++i) { scanf("%d%d",&x,&y); x++,y++; Add(x,y),Add(y,x); } for(int i = head[S]; i; i = next[i]) ans.num[0][i] = 1; for(int i = 2; i <= total; ++i) { int x = aim[i]; if(x == T) stack[++top] = i; for(int j = head[x]; j; j = next[j]) { if(j == (i^1)) continue; src.num[i][j] = 1; } } for(int i = 0; i <= total; ++i) temp.num[i][i] = 1; --t; while(t) { if(t&1) temp = temp * src; src = src * src; t >>= 1; } ans = ans * temp; int p = 0; for(int i = 1; i <= top; ++i) p = (p + ans.num[0][stack[i]]) % MO; cout << p << endl; return 0;}
BZOJ 1875 SDOI 2009 HH去散步 矩陣乘法最佳化DP