[TJOI 2017]可乐

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]$。

 1 //It is made by Awson on 2017.10.3
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <cstdio>
10 #include <string>
11 #include <cstring>
12 #include <cstdlib>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define Max(a, b) ((a) > (b) ? (a) : (b))
17 #define Min(a, b) ((a) < (b) ? (a) : (b))
18 #define sqr(x) ((x)*(x))
19 #define insert INSERT
20 using namespace std;
21 const int MOD = 2017;
22 void read(int &x) {
23     char ch; bool flag = 0;
24     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
25     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
26     x *= 1-2*flag;
27 }
28 
29 int n, m, u, v, t;
30 struct mat {
31     int a[35][35];
32     mat () {
33         memset(a, 0, sizeof(a));
34     }
35     mat (int _a[35][35]) {
36         for (int i = 0; i <= n; i++)
37             for (int j = 0; j <= n; j++)
38                 a[i][j] = _a[i][j];
39     }
40     mat operator * (const mat &b) const{
41         mat ans;
42         for (int i = 0; i <= n; i++)
43             for (int j = 0; j <= n; j++)
44                 for (int k = 0; k <= n; k++)
45                     (ans.a[i][j] += a[i][k]*b.a[k][j]) %= MOD;
46         return ans;
47     }
48 }S, T;
49 
50 void work() {
51     read(n), read(m);
52     for (int i = 1; i <= m; i++) {
53         read(u), read(v);
54         T.a[u][v] = T.a[v][u] = 1;
55     }
56     for (int i = 0; i <= n; i++)
57         T.a[i][0] = T.a[i][i] = 1;
58     S.a[0][1] = 1;
59     read(t);
60     while (t) {
61         if (t&1) S = S*T;
62         t >>= 1;
63         T = T*T;
64     }
65     int ans = 0;
66     for (int i = 0; i <= n; i++)
67         (ans += S.a[0][i]) %= MOD;
68     printf("%d
", ans);
69 }
70 int main() {
71     work();
72     return 0;
73 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/7623944.html