1. 程式人生 > >BZOJ4887: [Tjoi2017]可樂 矩陣快速冪

BZOJ4887: [Tjoi2017]可樂 矩陣快速冪

Description

加里敦星球的人們特別喜歡喝可樂。因而,他們的敵對星球研發出了一個可樂機器人,並且 放在了加里敦星球的1號城市上。這個可樂機器人有三種行為:停在原地,去下一個相鄰的 城市,自爆。它每一秒都會隨機觸發一種行為。現在給出加里敦星球城市圖,在第0秒時可 樂機器人在1號城市,問經過了t秒,可樂機器人的行為方案數是多少?  

Input

第一行輸入兩個正整數N,M表示城市個數,M表示道路個數。(1≤N≤30,0≤M≤100) 接下來M行輸入u,v表示u,v之間有一條道路。 (1≤u,v≤n)保證兩座城市之間只有一條路相連。 最後輸入時間t。1<t≤10^6

Output

 輸出可樂機器人的行為方案數,答案可能很大,請輸出對2017取模後的結果。

Sample Input

3 2
1 2
2 3
2

Sample Output

8

Solution

第一次做到這種以圖的形式的遞推用矩陣乘法優化的

貌似是套路題但是我不會啊T_T

於是觀摩了一波題解弄懂了這種型別的題目

一般是這種T很大N很小的題目就可以矩陣乘法優化

要求走T次就是對鄰接矩陣自乘T次...

/**************************************************************
    Problem: 4887
    User: henryy
    Language: C++
    Result: Accepted
    Time:80 ms
    Memory:1456 kb
***************************************************************
*/   #include <bits/stdc++.h>   using namespace std ;   #define mod 2017   int n , m ; struct matrix {     int m[ 100 ][ 100 ] ;     matrix() {         memset( m , 0 , sizeof( m ) ) ;     }     
int *operator[] ( int a ) { return m[ a ] ; }     matrix operator * ( matrix &x ) {         matrix ans ;         memset( ans.m , 0 , sizeof( ans.m ) ) ;         for( int i = 0 ; i <= n ; i ++ ) {             for( int j = 0 ; j <= n ; j ++ ) {                 for( int k = 0 ; k <= n ; k ++ ) {                     ans[ i ][ j ] = (ans[ i ][ j ] + m[ i ][ k ] * x[ k ][ j ] ) % mod ;                 }             }         }         return ans ;     } } a ;   matrix power( matrix x , int b ) {     matrix ans , base = x ;     for( int i = 0 ; i <= n ; i ++ ) ans[ i ][ i ] = 1 ;     while( b ) {         if( b & 1 ) ans = ans * base ;         base = base * base ;         b >>= 1 ;     }     return ans ; }   int main() {     scanf( "%d%d" , &n , &m ) ;     for( int i = 1 ; i <= m ; i ++ ) {         int x , y ;         scanf( "%d%d" , &x , &y ) ;         a[ x ][ y ] = a[ y ][ x ] = 1 ;     }     int t ;     scanf( "%d" , &t ) ;     for( int i = 0 ; i <= n ; i ++ ) a[ i ][ i ] = a[ i ][ 0 ] = 1 ;     a = power( a , t ) ;     int ans = 0 ;     for( int i = 0 ; i <= n ; i ++ ) {         ans = ( ans + a[ 1 ][ i ] ) % mod ;     }     printf( "%d\n" , ans ) ; }