cug 1436 A Strange Dream

1436: A strange dream

Time Limit: 5 Sec   Memory Limit: 128 MB
Submit: 17   Solved: 2
[ Submit][ Status][ Web Board]

Description

One day, Leo has a strange dream. In this dream, there are n scenes (marked from 1 to n). Each scene has a number pi. If Leo has x money at hand, when Leo enters the ith scene, his money will become least_common_multiple(x,pi). Notice that Leo will become mad if he goes to another scene but his money remain unchanged.
Suppose Leo is staying in the first scene (with p1 money). Please find out how many paths which can arrive at the nth scene and has k money there. Of course, you can't make Leo mad.
Two paths are regarded to be different if and only if the edge sequences are different. And we guarantee no repeated edge.

Input

There are multiple test cases. For each test case:
The first line contains three integer n (2 ≤ n ≤ 5000), m (2 ≤ m ≤ 20000) and k (2 ≤ k ≤ 10^6), as described above. Then followed by m lines. Each line contains two integer u, v (1 ≤ u, v ≤ n, u ≠ v), indicating that we can go to vth scene from uth scene directly. The last line of each case contains n integer pi (1 ≤ pi ≤ 10^6).
Process to the end of file. 

Output

One line for each case, output the number of paths mod 1000000007.

Sample Input

5 6 84
1 2
2 5
1 3
3 5
1 4
4 5
1 5 4 12 21

Sample Output

2

显然路径上的每一个点的钱都应该是K的约数,每个点的p也应该是K的约数
10^6以内的一个i,最多有240个约数
所以等于每个点最多240个状态.
用spfa可以求出对于所有点哪些状态是可达的
紧接着就可以用记忆化搜索求出路径数.
一开始在spfa里直接求路径数,这样只要某个点的某个状态的路径数改变了,这个点就要入队,无限TLE呀.....
但其实上每个点的每个状态最多只需进队一次的..


#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;

#define N 5005
#define M 250
#define MM 20005
#define mod 1000000007

inline int input(){
    int ret=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') ret=ret*10+c-'0',c=getchar();
    return ret;
}

int n,m,k,cnt;
int a[MM],b[MM],p[N],pp[M],fac[1000000+2],mut[M][M];
int dp[N][M];
bool val[N][M],inq[N];

struct EDGE{
    int v,next;
}edge[MM],rev[MM];
int head[MM],head1[MM],e,ee;
inline void add(int u,int v){
    edge[e].v=v;
    edge[e].next=head[u];
    head[u]=e++;

    rev[ee].v=u;
    rev[ee].next=head1[v];
    head1[v]=ee++;
}

inline int lcm(int a,int b){
    int x=a,y=b,t;
    while(y){
        t=x;
        x=y;
        y=t%x;
    }
    return a/x*b;
}

inline void Fun(int k){
    memset(fac,-1,sizeof(fac));
    cnt=0;
    for(int i=1;i*i<=k;i++){
        if(k%i==0){
            pp[cnt]=i,fac[i]=cnt,cnt++;
            if(k/i!=i){
                pp[cnt]=k/i,fac[k/i]=cnt,cnt++;
            }
        }
    }
    for(int i=0;i<cnt;i++){
        for(int j=i;j<cnt;j++){
            mut[i][j]=mut[j][i]=lcm(pp[i],pp[j]);
        }
    }
}

inline void spfa(){
    queue<int>q;
    memset(inq,0,sizeof(inq));
    memset(val,0,sizeof(val));
    q.push(1);
    val[1][fac[p[1]]]=1;

    inq[1]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        inq[x]=0;
        for(int j=0;j<cnt;j++){
            if(!val[x][j]) continue;
            if(j==k) continue;
            for(int i=head[x];i!=-1;i=edge[i].next){
                int v=edge[i].v;
                if(pp[j] % p[v]==0) continue;
                int vv=mut[j][fac[p[v]]];
                if(k%vv!=0) continue;
                if(val[v][fac[vv]]==1) continue;
                val[v][fac[vv]]=1;
                if(!inq[v]){
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
    }
}

inline int dfs(int x,int y){
    if(dp[x][fac[y]]!=-1) return dp[x][fac[y]];
    int ans=0;
    for(int i=head1[x];i!=-1;i=rev[i].next){
        int v=rev[i].v;
        for(int j=0;j<cnt;j++){
            if(pp[j]%p[x]==0) continue;
            if(!val[v][j]) continue;
            if(mut[j][fac[p[x]]] == y){
                ans += dfs(v,pp[j]);
                ans%=mod;
            }
        }
    }
    return dp[x][fac[y]]=ans%mod;
}

int main(){
    while(scanf("%d",&n)!=EOF){
        m=input(),k=input();
        Fun(k);

        for(int i=0;i<m;i++){
            a[i]=input(),b[i]=input();
        }
        for(int i=1;i<=n;i++){
            p[i]=input();
        }
        if(fac[p[1]]==-1 || fac[p[n]]==-1){
            puts("0");
        }
        else{
            memset(head,-1,sizeof(head));
            memset(head1,-1,sizeof(head1));
            e=ee=0;
            for(int i=0;i<m;i++){
                if(fac[p[a[i]]]==-1) continue;
                if(fac[p[b[i]]]==-1) continue;
                add(a[i],b[i]);
            }
            spfa();
            memset(dp,-1,sizeof(dp));
            memset(dp[1],0,sizeof(dp[1]));
            dp[1][fac[p[1]]]=1;
            printf("%d\n",dfs(n,k));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值