题目大意:给出一张无向图,求从A到B走k步(不能走回头路)的方案数。(k <= 2^30)
思路:看到k的范围就知道是矩阵乘法了。关键是不能走回头路怎么构造。正常的方法构造点的转移不能避免这个问题,就用边来构造。只要保证不经过自己^1的边就可以保证不走回头路了。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 210 #define MO 45989 using 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
原文地址:http://blog.csdn.net/jiangyuze831/article/details/41908867