HDU 5411(矩阵快速幂)

本题目意思:

给定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;
}



你可能感兴趣的:(HDU 5411(矩阵快速幂))