您的位置:首页 > 其它

HDU 5411 CRB and Puzzle(矩阵快速幂+可达矩阵)

2015-08-22 00:51 543 查看

HDU 5411

题意:

Count the number of different patterns by counting the number of different paths of length at most m-1.

思路:

其实这类问题就是求:

S=I+A+A2+...+AmS=I+A+A^2+...+A^m

一般普适的计算方式是:

(AmS)=(AI0I)m∗(I0)\left(
\begin{array}{ccc}
A^m\\
S\\
\end{array}
\right)
=\left(
\begin{array}{ccc}
A & 0\\
I & I\\
\end{array}
\right)^m
*
\left(
\begin{array}{ccc}
I\\
0\\
\end{array}
\right)

这样做的好处是可以得到最后的矩阵S,然后求S的所有元素和即是答案-1(没统计∅\emptyset),不过这题n <= 50 ,矩阵大小可能会超过100*100,时间复杂度将达到O(N3logM)O(N^3\log M)再加上数据有20组,会被卡常数TLE,但有一个办法就是将矩阵乘法的取模操作从最内层移到第二层(因为mod只有2015,也就是说矩阵最大元素只有2014,最内层的乘法加法操作不会爆int),可以进行一定常数优化,,刚好可以卡着时间AC(大概480ms)

但是这题并不需要我们求出最后的加和矩阵S,仅需要它的各项元素和即可,那么我们可以把这个矩阵简化成这样(假设邻接是个四阶矩阵):

⎛⎝⎜⎜⎜⎜⎜⎜11A1100001⎞⎠⎟⎟⎟⎟⎟⎟m=⎛⎝⎜⎜⎜⎜⎜⎜a1a2Ama3a40000a5⎞⎠⎟⎟⎟⎟⎟⎟\left(
\begin{array}{ccc}
&&& &0\\
&&&& 0\\
&&A& &0\\
&&&& 0\\
1& 1&1&1&1\\
\end{array}
\right)^m=
\left(
\begin{array}{ccc}
&&& &0\\
&&&& 0\\
&&A^m& &0\\
&&&& 0\\
a_1& a_2&a_3&a_4&a_5\\
\end{array}
\right)

ans=∑ni=1aians=\sum_{i=1}^na_i

这样做就避免了空间的浪费,且保留下来了答案,当然这里初始矩阵的最下面一行1也可以放去最上层,最左层,最右层,因为是计算AkA^k所有元素和,并无影响。

这种做法复杂度与之前一致,但因为矩阵大小降了近乎一半,耗时相对少了很多(大概93msAC)

代码:

方法1:

[code]/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const int maxn = 100 + 5 ;
const int mod = 2015 ;
struct Matrix {
    int n , m ;
    int a[maxn][maxn] ;
    Matrix( int n , int m ){
        this->n = n ;
        this->m = m ;
        cls(a) ;
    }
    Matrix operator * ( const Matrix &tmp ){
        Matrix res( n , tmp.m ) ;
        for( int i = 0 ; i < n ; i++ ){
            for( int j = 0 ; j < tmp.m ; j++ ){
                for( int k = 0 ; k < m ; k++ )
                    res.a[i][j] += a[i][k] * tmp.a[k][j] ;
                if( res.a[i][j] > mod ) res.a[i][j] %= mod ;
            }
        }
        return res ;
    }
};

void Matrix_print( Matrix x ){
    for( int i = 0 ; i < x.n ; i++ ){
        for( int j = 0 ; j < x.m ; j++ ){
            cout << x.a[i][j] << ' ';
        }
        cout << endl;
    }
    cout << endl ;
}
Matrix fast_pow( Matrix x , int n ){
    Matrix res( x.n , x.m ) ;
    for( int i = 0 ; i < x.n ; i++ ) res.a[i][i] = 1 ;
    while( n ){
        if( n & 1 )
            res = res * x ;
        n >>= 1 ;
        x = x * x ;
    }
    return res ;
}

int main(){
//  freopen("input.txt","r",stdin);
    int t  ; cin >> t ;
    while( t-- ){
        int n , m ;
        cin >> n >> m ;
        Matrix G( 2 * n , 2 * n ) ;
        for( int i = 0 ; i < n ; i++ ){
            int k ;
            scanf( "%d" , &k ) ;
            for( int j = 0 ; j < k ; j++ ){
                int tmp ;
                scanf( "%d" , &tmp ) ;
                G.a[i][tmp-1] = 1 ;
            }
        }
        for( int i = n ; i < 2 * n ; i++ ){
            G.a[i][i - n] = 1 ;
            G.a[i][i] = 1 ;
        }
        Matrix base( 2 * n , n ) ;
        for( int i = 0 ; i < n ; i++ )
            base.a[i][i] = 1 ;
        G = fast_pow( G , m  );
        //Matrix_print( G ) ;
        base = G * base ;
        //Matrix_print( base ) ;
        int ans = 0 ;
        for( int i = n ; i < 2 * n ; i++ )
            for( int j = 0 ; j < n ; j++ )
                ans += base.a[i][j] ;
        cout << ( ans + 1 ) % mod << endl ;
    }
    return 0;
}


方法2:

[code]/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>

using namespace std;

#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;

const int maxn = 100 + 5 ;
const int mod = 2015 ;
struct Matrix {
    int n , m ;
    int a[maxn][maxn] ;
    Matrix( int n , int m ){
        this->n = n ;
        this->m = m ;
        cls(a) ;
    }
    Matrix operator * ( const Matrix &tmp ){
        Matrix res( n , tmp.m ) ;
        for( int i = 0 ; i < n ; i++ ){
            for( int j = 0 ; j < tmp.m ; j++ ){
                for( int k = 0 ; k < m ; k++ )
                    res.a[i][j] += a[i][k] * tmp.a[k][j] ;
                if( res.a[i][j] > mod ) res.a[i][j] %= mod ;
            }
        }
        return res ;
    }
};

void Matrix_print( Matrix x ){
    for( int i = 0 ; i < x.n ; i++ ){
        for( int j = 0 ; j < x.m ; j++ ){
            cout << x.a[i][j] << ' ';
        }
        cout << endl;
    }
    cout << endl ;
}
Matrix fast_pow( Matrix x , int n ){
    Matrix res( x.n , x.m ) ;
    for( int i = 0 ; i < x.n ; i++ ) res.a[i][i] = 1 ;
    while( n ){
        if( n & 1 )
            res = res * x ;
        n >>= 1 ;
        x = x * x ;
    }
    return res ;
}

int main(){
//  freopen("input.txt","r",stdin);
    int t  ; cin >> t ;
    while( t-- ){
        int n , m ;
        cin >> n >> m ;
        Matrix G( n + 1 , n + 1 ) ;
        for( int i = 0 ; i < n ; i++ ) G.a
[i] = 1 ;
        for( int i = 0 ; i < n ; i++ ){
            int k ;
            scanf( "%d" , &k ) ;
            for( int j = 0 ; j < k ; j++ ){
                int tmp ;
                scanf( "%d" , &tmp ) ;
                G.a[i][tmp-1] = 1 ;
            }
        }
        //Matrix_print( G ) ;
        G = fast_pow( G , m );
        //Matrix_print( G ) ;
        int ans = 0 ;
        for( int i = 0 ; i <= n ; i++ )
            ans += G.a
[i] ;
        cout << ( ans ) % mod << endl ;
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: