这个题目必须得记录一下,经典。
dp【i】【j】 i表示现在在哪个点,j表示现在是第几个约数,记忆化搜索即可,做了一些题之后,发现这是个经典的设置状态方法。
#include<stdio.h> #include<string.h> #include<math.h> #include<map> #define MOD 1000000007 #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define LL long long using namespace std; const int maxn = 20005; struct edge { int u,v,next; }e[maxn]; map<LL,int> mp; int n,m,K,dp[2005][1005]; int head[2005],tot,get[2005]; void add_edge(int u,int v); int dfs(int now,LL x); void init(); LL gcd(LL a,LL b){ return b==0?a:gcd(b,a%b); }//最大公约数 LL lcm(LL a,LL b){ return a/gcd(a,b)*b; }//最小公倍数 int main() { int i; while(scanf("%d%d%d",&n,&m,&K) != EOF) { memset(dp,-1,sizeof(dp)); memset(head,-1,sizeof(head)); tot = 0; for(i = 0;i < m;i ++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); } for(i = 1;i <= n;i ++) scanf("%d",&get[i]); init(); if(mp.find(get[1]) == mp.end()) { printf("0\n"); continue; } printf("%d\n",dfs(1,get[1])); } return 0; } void add_edge(int u,int v) { e[tot].u = u,e[tot].v = v; e[tot].next = head[u],head[u] = tot ++; } void init() { int i,j,cnt = 0; mp.clear(); for(i = 1;i <= sqrt(K);i ++) { if(K % i) continue; mp[i] = cnt ++; mp[K / i] = cnt ++; } } int dfs(int now,LL x) { if(dp[now][mp[x]] != -1) return dp[now][mp[x]]; if(now == n) { if(x == K) return dp[now][mp[x]] = 1; else return dp[now][mp[x]] = 0; } int i,sum = 0; map<LL,int>:: iterator it; for(i = head[now];i != -1;i = e[i].next) { int v = e[i].v; LL y = lcm(x,get[v]); if(y == x) continue; it = mp.find(y); if(it == mp.end()) continue; sum += dfs(v,y); sum %= MOD; } return dp[now][mp[x]] = sum; }