题目描述
加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的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。
题解
pgy said:这道题的唯一难一点的地方就是怎么处理“自爆”和“停在原地”
蒟蒻我看到题目就想起来了,然而,并不知道要用矩阵快速幂
似乎答案特别大的题目啦,要模一个数的题目啦,统计方案数的题目啦,就是矩阵快速幂优化DP的
然后我们看一下这道题:
以前有写过图的矩阵快速幂看这里
对于本题,我们可以把它当做从1开始,走t步恰好到达i (1<=i<=n)的方案数
已知G^[i][j]表示从i开始到j为止走了k步的路径数,是不是很显然了 qwq
最后还是说一下开始提到的 自爆 和 留在原地 的问题
自爆嘛 就是连一个到0的边(但是程序里写的好像是n+1,将就着看吧)这样就再也出不来了,像死了一样
留在原地更简单了 加一个自环呗
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=2017;
ll n,j,k,t,y,x,anss,m,f[1001];
struct matrix
{
ll a[101][101];
matrix(){memset(a,0,sizeof(a));}
}a,ans;
matrix operator *(const matrix &x,const matrix &y)
{
matrix z;int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
return z;
}
int main()
{
int i;
scanf("%d%d",&n,&m);
n++;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
a.a[x][y]=1;
a.a[y][x]=1;
}
for(i=1;i<=n;i++)
{
a.a[i][n]=1;
a.a[i][i]=1;
}
for(i=1;i<=n;i++)ans.a[i][i]=1;
scanf("%d",&k);
do
{
if(k&1)ans=ans*a;
a=a*a;k>>=1;
}while(k);
for(i=1;i<=n;i++)
anss=(anss+ans.a[1][i])%mod;
printf("%d\n",anss);
return 0;
}