标签:clu 没有 for bsp mic 答案 operator bzoj 输出
题目描述
输入
输出
一行,表示答案。
样例输入
4 5 3 0 0
0 1
0 2
0 3
2 1
3 2
样例输出
4
题解
矩阵乘法
“每一次不能立刻沿着上一次的边的反方向返回”这个条件的限制导致不能直接进行矩阵乘法。
由于边数很少,我们可以换个思路:把边看作矩阵乘法的行列,矩阵中的元素表示 从一条边走到另一条边的方案数。
那么对于两条边$i,j$,如果不是刚走过来的边并且能够接上($y_i=x_j$),则$A_{ij}=1$。
然后建立两个虚点,第一个向起点为s的边连边,起点为t的项第二个连边。
然后快速幂矩阵乘法即可。
时间复杂度$O(m^3\log t)$
#include <cstdio> #include <cstring> #define N 130 #define mod 45989 int m , px[N] , py[N]; struct data { int v[N][N]; data() {memset(v , 0 , sizeof(v));} int* operator[](int a) {return v[a];} data operator*(data a) { data ans; int i , j , k; for(i = 0 ; i <= m ; i ++ ) for(j = 0 ; j <= m ; j ++ ) for(k = 0 ; k <= m ; k ++ ) ans[i][j] = (ans[i][j] + v[i][k] * a[k][j]) % mod; return ans; } }a; data pow(data x , int y) { data ans; int i; for(i = 0 ; i <= m ; i ++ ) ans[i][i] = 1; while(y) { if(y & 1) ans = ans * x; x = x * x , y >>= 1; } return ans; } int main() { int n , k , s , t , i , j; scanf("%d%d%d%d%d" , &n , &m , &k , &s , &t); for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &px[i << 1] , &py[i << 1]) , px[i << 1 | 1] = py[i << 1] , py[i << 1 | 1] = px[i << 1]; m = m * 2 + 1; for(i = 2 ; i <= m ; i ++ ) { if(px[i] == s) a[0][i] = 1; if(py[i] == t) a[i][1] = 1; for(j = 2 ; j <= m ; j ++ ) if(py[i] == px[j] && (i ^ j) != 1) a[i][j] = 1; } a = pow(a , k + 1); printf("%d\n" , a[0][1]); return 0; }
【bzoj1875】[SDOI2009]HH去散步 矩阵乘法
标签:clu 没有 for bsp mic 答案 operator bzoj 输出
原文地址:http://www.cnblogs.com/GXZlegend/p/7602896.html