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 }