P3758 [TJOI2017]可乐(矩阵加速)

题目描述

加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的 11 号城市上。这个可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。现在给加里敦星球城市图,在第 00 秒时可乐机器人在 11 号城市,问经过了 tt 秒,可乐机器人的行为方案数是多少?

输入格式

第一行输入两个正整数 NN,MM。NN 表示城市个数,MM 表示道路个数。

接下来 MM 行每行两个整数 uu,vv,表示 uu,vv 之间有一条道路。保证两座城市之间只有一条路相连,且没有任何一条道路连接两个相同的城市。

最后一行是一个整数 tt,表示经过的时间。

输出格式

输出可乐机器人的行为方案数,答案可能很大,请输出对 20172017 取模后的结果。

题解:

假设现在有一个邻接矩阵A,那么A^k的意义是,A^k的第i行第j列的数字含义是从第i到j经过k步的路径总数。

从这个角度出发,可以先把这道题的邻接矩阵建出来,然后算这个矩阵的k次方。

最后统计A(1,i)的和就是答案。

在原地停留的情况,就是每个点和自己建一个自环即可。

自爆的情况,可以新建一个编号为0的城市,这个点除了自己外不连出边

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int mod=2017;
int t;
int n,m;
struct matrix {
    int m[40][40];
}ans,base;
void init () {
    memset(ans.m,0,sizeof(ans.m));
    for (int i=0;i<=30;i++) ans.m[i][i]=1;
    memset(base.m,0,sizeof(base.m));
}
matrix mul (matrix a,matrix b) {
    matrix wjm;
    memset(wjm.m,0,sizeof(wjm.m));
    for (int i=0;i<=30;i++)    
        for (int j=0;j<=30;j++)
            for (int k=0;k<=30;k++)
                wjm.m[i][j]=(wjm.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
    return wjm;
}
void qpow (int p) {
    while (p) {
        if (p&1) ans=mul(ans,base);
        base=mul(base,base);
        p>>=1;
    }
}
int main () {
    scanf("%d%d",&n,&m);
    init();
    for (int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        base.m[x][y]=1;
        base.m[y][x]=1;
    }
    for (int i=0;i<=n;i++) base.m[i][i]=1;
    for (int i=1;i<=n;i++) base.m[i][0]=1;
    scanf("%d",&t);
    qpow(t);
    int Ans=0;
    for (int i=0;i<=n;i++) Ans=(Ans+ans.m[1][i])%mod;
    printf("%d\n",Ans);
}

 

posted @ 2020-08-19 21:58  zlc0405  阅读(171)  评论(0编辑  收藏  举报