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 }

 

 

posted @ 2012-10-01 22:44  dgsrz  阅读(278)  评论(0编辑  收藏  举报