zoj 3644(dp + 记忆化搜索)

时间:2022-03-23 07:20:29

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834

思路:dp[i][j]表示当前节点在i,分数为j的路径条数,从题中可以得出,要在N处的分数为K,那么那些到达N的路径上的节点的val必然是K的因子,由于K的范围为[1, 1000000],二维数组开不下,那么我们可以用一个数组来保留K的所有因子,在用一个数组来保留这个因子的值,这样,二维数组就可开了,于是,就是记忆化搜索了!

 /*************************************************************************
> File Name: zoj3644.cpp
> Author: syhjh
> Created Time: 2014年03月18日 星期二 20时47分15秒
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int MAXN = ( + );
const int MAXM = ( + );
const int MAX = ( + );
const int MOD = ();
template < class T > inline T GCD(T a, T b)
{
return b == ? a : GCD(b, a % b);
} template < class T > inline T LCM(T a, T b)
{
return a / GCD(a, b) * b;
} struct Edge {
int v, next;
} edge[MAXM]; int N, M, K, val[MAXN];
int NE, head[MAXN]; void Insert(int u, int v)
{
edge[NE].v = v;
edge[NE].next = head[u];
head[u] = NE++;
} int dp[MAXN][MAXN];
int pp[MAX], num[MAXN]; void Init()
{
memset(pp, -, sizeof(pp));
int cnt = ;
for (int i = ; i <= K; i++) {
if (K % i == ) {
pp[i] = cnt;
num[cnt++] = i;
}
}
} int getDp(int u, int s)
{
if (s == -) return ;
if (u == N && num[s] == K) {
return ;
}
if (dp[u][s] != - ) return dp[u][s];
int ans = ;
for (int i = head[u]; i != -; i = edge[i].next) {
int v = edge[i].v;
if (K % val[v]) continue;
int tmp = LCM(num[s], val[v]);
if (tmp != num[s] && K % tmp == ) {
ans += getDp(v, pp[tmp]);
ans %= MOD;
}
}
return dp[u][s] = ans;
} int main()
{
while (cin >> N >> M >> K) {
NE = ;
memset(head, -, sizeof(head));
while (M--) {
int u, v;
cin >> u >> v;
Insert(u, v);
}
for (int i = ; i <= N; i++) {
cin >> val[i];
}
Init();
memset(dp, -, sizeof(dp));
cout << getDp(, pp[val[]]) << endl;
}
return ;
}