本题目意思:
给定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;
}