/**//* 给出一个图,询问T时间内from->to的方法数。t<=10^9 , n<=50 但每个点向外的边有周期性,在某些时刻会开,某些时刻没有 周期<=6 人可在点停留
请教hhanger的 Orz 矩阵M[t]表示t时刻i->j的方法数 那么M[t] = M[t-1]*A[t] A[t]为t时刻图的邻接表 M[0] = I M[1] = M[0]*A[1] M[2] = M[1]*A[2] = A[1]*A[2] M[60] = A[1]*A[2]A[60] M[61] = A[1]*A[2]*A[60]*A[61] 注意到,每个点的周期是[1,6] 所以60是他们的LCM周期 所以A[61] = A[1] M[61] = M[60] * A[1] . M[k*60 + t0] = M[60]^k * M[t0] 对于这个幂就可以用矩阵乘法了 对T/60个M[60]矩阵用矩阵乘法 , 剩下的T%60就是M[T%60] */ #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> #include<map> #include<cmath> #include<cstdlib> #include<iostream>
using namespace std;
const int INF = 1000000000; const int MOD = 100000007; const int MAXN = 50;
int n , T; long long U[MAXN][MAXN]; long long A[65][MAXN][MAXN];
void imul(long long C[][MAXN] , long long A[][MAXN] , long long B[][MAXN]) // C = A * B { long long R[MAXN][MAXN] = {0}; for(int k = 0 ; k < n; k++) for(int i = 0 ; i < n ; i++) if(A[i][k]) { for(int j = 0 ; j <n; j ++) R[i][j] += A[i][k] * B[k][j]; } for(int i = 0 ; i < n; i++) for(int j = 0 ; j < n ; j++) C[i][j] = R[i][j] % MOD; }
void ipow(long long R[][MAXN] , int K) { if(K == 0) { for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) R[i][j] = (i==j); return ; } if(K == 1) { for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) R[i][j] = U[i][j]; return ; } ipow(R , K / 2); imul(R , R , R); if(K&1)imul(R , R , U); }
int main() {
#ifdef ONLINE_JUDGE #else freopen("in", "r", stdin); #endif
int from , to; while( ~scanf("%d%d%d%d",&n,&T,&from,&to) ) { for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) scanf("%d",&A[0][i][j]); for(int j = 0 ; j < n ; j++) A[0][to][j] = 0;
int num , x; for(int i = 0 ; i < n ; i++) { scanf("%d",&num); for(int jj = 1 ; jj <= num ; jj++) { scanf("%d",&x); for(int k = 0 ; num*k + jj <= 60 ; k++) { for(int j = 0 ; j < n ;j++) A[num*k + jj][i][j] = x & A[0][i][j]; A[num*k + jj][i][i] = 1; } } }
int limit = min(60 , T);
for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n; j++) A[0][i][j] = (i==j); for(int k = 1 ; k <= limit ; k++) { imul(A[k] , A[k-1] , A[k]);//M[k] = M[k-1] * A[k] } for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n; j++) U[i][j] = A[60][i][j];//M[60]
int K = T / 60 , left = T % 60; long long R[MAXN][MAXN]; ipow(R,K); imul(R,R,A[left]); printf("%lld\n",R[from][to]); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|