[TJOI 2017]可乐

时间:2022-04-08 08:13:32

Description

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

Input

第一行输入两个正整数况N,M,N表示城市个数,M表示道路个数。(1 <= N <=30,0 < M < 100)

接下来M行输入u,v,表示u,v之间有一条道路。(1<=u,v <= n)保证两座城市之间只有一条路相连。

最后输入入时间t

Output

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

Sample Input

3 2
1 2
2 3
2

Sample Output

8

HINT

【样例解释】

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$:

$f[i][j][0]$表示第$i$时刻,在城市$j$爆炸的方案数,$f[i][j][1]$表示第i时刻,在城市$j$不爆炸的方案数

$f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]$,$f[i][j][1]=f[i][j][1]+f[i][k][1]$($k$是$j$的相邻结点)

这样是要$MLE$的,显然状态的答案只与前一状态相关,直接滚动即可

可是依旧$T$了。

我们发现是城市数量很少,用邻接矩阵存。有矩阵的话就可以矩阵加速了。

我们定义矩阵$S$为$1*(n+1)$答案矩阵,$S[0][0]$表示$t$秒前(包括$t$秒)爆炸的方案总数;$S[0][i]$,$1<=i<=n$表示$t$秒时在点$i$的方案总数,初始$S[0][1]=1$;

矩阵$T$为$(n+1)*(n+1)$的邻接矩阵,除此之外:注意$T[i][0]=1$,$0<=i<=n$为了统计“爆炸”的情况;$T[i][i]=1$表示停在$i$点不动。

显然我们需要$S*=T^t$,最后答案就是$\sum _{i=0} ^n S[0][i]$。

 //It is made by Awson on 2017.10.3
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define sqr(x) ((x)*(x))
#define insert INSERT
using namespace std;
const int MOD = ;
void read(int &x) {
char ch; bool flag = ;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || ); ch = getchar());
for (x = ; isdigit(ch); x = (x<<)+(x<<)+ch-, ch = getchar());
x *= -*flag;
} int n, m, u, v, t;
struct mat {
int a[][];
mat () {
memset(a, , sizeof(a));
}
mat (int _a[][]) {
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
a[i][j] = _a[i][j];
}
mat operator * (const mat &b) const{
mat ans;
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++)
for (int k = ; k <= n; k++)
(ans.a[i][j] += a[i][k]*b.a[k][j]) %= MOD;
return ans;
}
}S, T; void work() {
read(n), read(m);
for (int i = ; i <= m; i++) {
read(u), read(v);
T.a[u][v] = T.a[v][u] = ;
}
for (int i = ; i <= n; i++)
T.a[i][] = T.a[i][i] = ;
S.a[][] = ;
read(t);
while (t) {
if (t&) S = S*T;
t >>= ;
T = T*T;
}
int ans = ;
for (int i = ; i <= n; i++)
(ans += S.a[][i]) %= MOD;
printf("%d\n", ans);
}
int main() {
work();
return ;
}