ZOJ 3644 Kitty's Game
这一次的浙大月赛依旧被虐惨。。。比赛中途还要去上课,坑爹=。=
A题比赛时想的差不多了,没敲。。
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3644
大意:从有向图的1号点出发,X初始为1号点的分数。每途径一个结点,X更新为X与当前结点的最小公倍数。且规定每次到达一个结点,X的值必须发生变化。求出有多少种方案可以从1号点走到N号点,且X=k。
题解:记忆化搜索。dp[i][j] 保存到达i结点、X为j时的方案总数。分析题目可以发现,每一步可行的走法下X始终是k的因子。由于X可以很大,不妨将k的所有因子用map哈希下,这样二维数组就开的下了。另外可以发现,即使dfs进入环,由于继续在环内递归其X将恒等于进入环时的X,因此算法可以在有限步后结束。
1 //=========================================== 2 // Name : ZOJ3644.cpp 3 // Author : dgsrz 4 // Description : Memoization-DP 5 //=========================================== 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <cmath> 11 #include <map> 12 using namespace std; 13 14 typedef long long LL; 15 const int N = 2005; 16 const int M = 20005; 17 const LL MOD = 1000000007; 18 struct Node { 19 int v, next; 20 } e[M]; 21 map<LL, int> fac; 22 int head[N], edge, n, m, k, idx; 23 LL dp[N][N], val[N], ans; 24 25 LL gcd(LL a, LL b) { 26 return (b != 0) ? gcd(b, a % b) : a; 27 } 28 29 LL lcm(LL a, LL b) { 30 return a / gcd(a, b) * b; 31 } 32 33 LL dfs(LL x, int u) { 34 if (dp[u][fac[x]] != 0) { 35 return dp[u][fac[x]]; 36 } 37 if (u == n) { 38 return x == k; 39 } 40 for (int i = head[u]; i != -1; i = e[i].next) { 41 int v = e[i].v; 42 if (k % val[v] != 0) continue; //若val[v]不是k的因子则无意义 43 LL lcm_x = lcm(x, val[v]); 44 if (lcm_x == x || lcm_x > k) continue; //若当前的x和上一步相同则不合法 45 dp[u][fac[x]] += dfs(lcm_x, v); 46 } 47 return (dp[u][fac[x]] %= MOD); 48 } 49 50 void addEdge(int u, int v) { 51 e[edge].v = v; 52 e[edge].next = head[u]; 53 head[u] = edge++; 54 } 55 56 void getFactor() { 57 idx = 0; 58 int limit = (int)sqrt(1.0 * k); 59 fac.clear(); 60 for (int i = 1; i < limit; i++) { 61 if (k % i == 0) { 62 fac[i] = idx++; 63 fac[k / i] = idx++; 64 } 65 } 66 if (k % limit == 0) { 67 fac[limit] = idx++; 68 } 69 }//取得k的所有因子并哈希 70 71 int main() { 72 while (~scanf("%d%d%d", &n, &m, &k)) { 73 memset(head, -1, sizeof(head)); 74 edge = 0; 75 ans = 0; 76 getFactor(); 77 for (int i = 0; i < m; i++) { 78 int u, v; 79 scanf("%d%d", &u, &v); 80 addEdge(u, v); 81 } 82 for (int i = 1; i <= n; i++) { 83 scanf("%lld", &val[i]); 84 } 85 memset(dp, 0, sizeof(dp)); 86 ans = dfs(val[1], 1); 87 printf("%lld\n", ans); 88 } 89 return 0; 90 }