DestinHistoire

 

BZOJ-4887 [Tjoi2017]可乐(邻接矩阵的幂)

题目描述

  有一个 \(n(1\leq n\le 30)\) 个点 \(m(0< m\leq 100)\) 条边的无向图,在第 \(0\) 秒,点 \(1\) 有一个机器人,这个机器人有三种行为:停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。问经过了 \(t(1\leq t\leq 10^6)\) 秒,机器人的行为方案数是多少。

分析

  停在原地相当于每个点都有一个到本身的自环;自爆相当于去点 \(0\),其他所有点都有连向点 \(0\) 的一条有向边,但点 \(0\) 除了连向自身的自环外没有任何出边,这样满足了任意一个点都可以自爆,且无法恢复到其他状态。对邻接矩阵求 \(t\) 次幂,设结果为 \(A\),答案为 \(\displaystyle\sum_{i=1}^{n}A[1][i]\)

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,t;
const int mod=2017;
struct matrix
{
    int mat[310][310];
    matrix()
    {
        memset(mat, 0, sizeof(mat));
    }
}A;
matrix mul(matrix A,matrix B)
{
    matrix ans;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            for(int k=0;k<=n;k++)
                ans.mat[i][j]=(ans.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod;
    return ans;
}
matrix matrix_pow(matrix a,int b)
{
    matrix ans;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            ans.mat[i][j]=(i==j);
    while(b)
    {
        if(b&1)
            ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
    }
    return ans;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        A.mat[x][y]=1;
        A.mat[y][x]=1;
    }
    for(int i=0;i<=n;i++)
        A.mat[i][i]=1;
    for(int i=1;i<=n;i++)
        A.mat[i][0]=1;
    int ans=0;
    cin>>t;
    A=matrix_pow(A,t);
    for(int i=0;i<=n;i++)
        ans=(ans+A.mat[1][i])%mod;
    cout<<ans<<endl;
    return 0;
}

posted on 2020-11-20 21:47  DestinHistoire  阅读(103)  评论(0)    收藏  举报

导航