http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834
从点1出发,假设现在在i,点数为sta,则下一步的点数必然不能是sta的因数,所以不会形成环,只需从1直接走,走到n即可.
但是如果这样的话时空复杂度就都是nk,明显不满足题意,而这个时候我们可以想到,每个状态都必然是k的约数,(点数不是k的约数的节点不在路上,可以无视),而约数的个数也就k^0.5个,可以直接用map映射,这样时空复杂度都是n*k^0.5,可以解出答案.
一开始直接用dfs,结果TLE了.
#include <cstdio> #include <cstring> #include <map> using namespace std; const int maxn = 2001; const int maxm = 2e4+4; const int mod = 1000000007; const int maxk = 1e6+6; int n,m,k; int p[maxn]; typedef long long ll; map<int ,int >id; ll dp[maxn][maxn]; int first[maxn]; struct edge{ int nxt,t; }e[maxm]; void addedge(int f,int t,int ind){ e[ind].nxt = first[f]; e[ind].t = t; first[f] = ind; } int bit[30],num; void apart(int k){ for(int i=2;i*i<=k;i++){ while(k%i==0){ bit[num++]=i; k/=i; } } if(k>1)bit[num++]=k; } ll gcd(ll a,ll b){ if(b==0)return a; return gcd(b,a%b); } ll lcm(ll a,ll b){ return a*b/gcd(a,b); } bool vis[maxn]; int cnt; ll dfs(int s,int sav){ if(id[sav]!=0&&dp[s][id[sav]]!=0)return dp[s][id[sav]]; if(s==n)return sav==k?1:0; vis[s]=true; if(id[sav]==0)id[sav]=++cnt; for(int pe=first[s];pe!=-1;pe=e[pe].nxt){ int t=e[pe].t; ll lcmnum=lcm(p[t],sav); if(vis[t]||lcmnum==sav||lcmnum>k)continue; dp[s][id[sav]]+=dfs(t,lcmnum); dp[s][id[sav]]%=mod; } vis[s]=false; return dp[s][id[sav]]; } int solve(){ num=0; apart(k); if(lcm(p[1],k)!=k||lcm(p[n],k)!=k)return 0; for(int i=2;i<n;i++){ if(lcm(p[i],k)!=k){ vis[i]=true; } } return dfs(1,p[1]); } void init(){ memset(first,-1,sizeof first); memset(dp,0,sizeof dp); memset(vis,0,sizeof vis); cnt=0; id.clear(); } int main(){ while(scanf("%d%d%d",&n,&m,&k)==3){ init(); for(int i = 0;i < m;i++){ int f,t; scanf("%d%d",&f,&t); addedge(f,t,i); } for(int i = 1;i <= n;i++){ scanf("%d",p+i); } int ans=solve(); printf("%d ",ans); } return 0; }