本题目意思:
给定n个点,给定一个n*n的转移矩阵,要求求出所有长度不大于M的序列个数,(M<=1E5 , n <= 50)
分析:
记 d[i][j] 生成至多长度为i的且以j开头的所有串的个数,d[i+1][j] = sum( d[ i][ k ] )+1( 其中 j->k可达)
那么
记矩阵tran (n+1,n+1)=
[ 0
A, 0
.
.
1,1,1,1.....1](其中A为转移矩阵)
[d[i][1],d[i][2], d[i][3]....d[i ][n], 1 ] * tran = [d[i+1][1],d[i+1][2], d[i+1][3]....d[i+1 ][n], 1 ];
这样先把tran快速幂M-1次,在求和即可。复杂度 (n^3*log(m));
自己第一开始是用的正推的公式,怎么也建不出转移矩阵,倒着推得好理解,好建矩阵,主要是矩阵当前矩阵只用来获取等号左边的值而不是右边。
#include<cstring> #include<cstdio> #include<algorithm> #include <iostream> using namespace std; const int N = 55; #define rep(i,n) for(int i=0;i<(int)n;i++) #define rep1(i,x,y) for(int i=x;i<=(int)y;i++) int n,m; struct Matrix{ int m[N][N]; void init(){memset(m,0,sizeof(m)); } void standard(){ rep1(i,0,n) rep1(j,0,n) m[i][j]=(i==j); } void show(){ rep1(i,0,n) rep1(j,0,n){cout<<m[i][j]<<" "; if(j==n) cout<<endl;} } }; const int mod = 2015; Matrix mul(Matrix A,Matrix B){ Matrix C; rep1(i,0,n) rep1(j,0,n){ C.m[i][j]=0; rep1(k,0,n) C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j])%mod; } return C; } Matrix pow_mul(Matrix A,int b){ Matrix ans; ans.standard(); while(b){ if(b&1) ans=mul(ans,A); A=mul(A,A); b>>=1; } return ans; } int main() { int T; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); Matrix A; A.init(); rep(i,n){ int k ,x; scanf("%d",&k); rep(j,k){ scanf("%d",&x); --x; A.m[x][i]=1; } } rep1(i,0,n) A.m[n][i]=1; if(m == 0) { printf("1\n"); continue;} A = pow_mul(A,m-1); int ans = 0; rep1(i,0,n) rep1(j,0,n) ans=(ans+A.m[i][j])%mod; printf("%d\n",ans); } return 0; }