1. 程式人生 > >洛谷P3758:[TJOI2017]可樂

洛谷P3758:[TJOI2017]可樂

sca gpo -m 範圍 opera n+1 兩個 matrix 快速冪

題目描述

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

輸入輸出格式

輸入格式

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

輸出格式

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

輸入輸出樣例

輸入樣例#1

3 2
1 2
2 3
2

輸出樣例#1

8

說明

【樣例解釋】

1 ->爆炸
1 -> 1 ->爆炸
1 -> 2 ->爆炸
1 -> 1 -> 1
1 -> 1 -> 2
1 -> 2 -> 1
1 -> 2 -> 2
1 -> 2 -> 3

【數據範圍】

對於20%的pn,有1 < t ≤ 1000
對於100%的pn,有1 < t ≤ 10^6。


想法

很顯然的dp
n這麽小,可以矩陣加速
進行快速冪的矩陣共n+1列,前n列為某個點與其他點的連接情況,最後一列全是1,計算某一秒自爆的方案數


代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

#define P 2017

using namespace std;

const int N = 35;

struct matrix{
    int a[N][N];
    void clear(){
        for(int i=1;i<N;i++)
            for(int j=1;j<N;j++)
                a[i][j]=(i==j);
    }
    matrix operator * (const matrix &b) const{
        matrix c;
        for(int i=1;i<N;i++)
            for(int j=1;j<N;j++){
                c.a[i][j]=0;
                for(int k=1;k<N;k++)
                    c.a[i][j]=(c.a[i][j]+(a[i][k]*b.a[k][j])%P)%P;
            }
        return c;
    }
};

int n,m,t;
matrix map;

matrix pow_mod(matrix b,int x){
    matrix ret;
    ret.clear();
    while(x){
        if(x&1) ret=ret*b;
        b=b*b;
        x>>=1;
    }
    return ret;
}

int main()
{
    int u,v;
    scanf("%d%d",&n,&m);
    map.clear();
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        map.a[u][v]=map.a[v][u]=1;
    }
    for(int i=1;i<=n+1;i++)
        map.a[i][n+1]=1;
    scanf("%d",&t);
    
    matrix a;
    memset(a.a,0,sizeof(a.a));
    a.a[1][1]=1;
    a=a*pow_mod(map,t);
    
    int ans=0;
    for(int i=1;i<=n+1;i++)
        ans=(ans+a.a[1][i])%P;
    printf("%d\n",ans);
    
    return 0;
}

洛谷P3758:[TJOI2017]可樂