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); }