zoukankan      html  css  js  c++  java
  • [LUOGU] P3953 逛公园

    https://www.luogu.org/problemnew/show/P3953

    第一反应,设计状态f[x][res]表示到达x点,到终点还能比最短路多走res距离的方案数。

    转移时枚举下一个点,记忆化搜索。

    但是这样是不对的,会有不能访问的点。

    所以应该从终点开始进行记忆化搜索,建反图就可以了。

    找0环,本质就是是否存在一个点,两次访问的时候res都相同,可以用一个桶记录一下。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    
    using namespace std;
    
    const int MAXN=200005;
    const int INF=1<<29;
    
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=getchar();
      return ret*f;
    }
    
    struct Edge{
      int next,to,w;
    }e[MAXN],e2[MAXN];
    int head[MAXN],ecnt;
    inline void add(int x,int y,int w){
      e[++ecnt].next = head[x];
      e[ecnt].to = y;
      e[ecnt].w = w;
      head[x] = ecnt;
    }
    int head2[MAXN],ecnt2;
    inline void add2(int x,int y,int w){
      e2[++ecnt2].next = head2[x];
      e2[ecnt2].to = y;
      e2[ecnt2].w = w;
      head2[x] = ecnt2;
    }
    int n,m,mod,num;
    
    struct Node{
      int id,w;
      Node(int x=0,int y=0){id=x;w=y;}
      bool operator<(const Node &rhs) const {
        return w>rhs.w;
      }
    };
    
    int dis[MAXN],vis[MAXN];
    priority_queue<Node>Q;
    void dij(){
      while(!Q.empty()) Q.pop();
      for(int i=0;i<=n;i++) dis[i]=INF;
      memset(vis,0,sizeof(vis));
      dis[n]=0;
      for(int i=1;i<=n;i++){Q.push(Node(i,dis[i]));}
      for(int i=1;i<=n;i++){
        int mn,mnid;
        Node tmp;
        do{
          tmp=Q.top();
          Q.pop();
        }while(vis[tmp.id]);
        mn=tmp.w;mnid=tmp.id;
        vis[mnid]=1;
        for(int j=head[mnid];j;j=e[j].next){
          int v=e[j].to,w=e[j].w;
          if(dis[v]>mn+w){
            dis[v]=mn+w;
            Q.push(Node(v,dis[v]));
          }
        }
      }
    }
    
    int f[MAXN][64],ins[MAXN][64];
    bool flag=0;
    
    int dfs(int x,int res){
    
      if(ins[x][res]) return flag=1,0;
      if(flag) return 0;
      if(~f[x][res]) return f[x][res];
      ins[x][res]=1;
    
      int &ret=f[x][res]=0;
      for(int i=head2[x];i;i=e2[i].next){
        int v=e2[i].to;
        if(dis[v]==INF) continue;
        int tmp=res-(e2[i].w-dis[x]+dis[v]);
        if(tmp<0||tmp>num) continue;
        ret+=dfs(v,tmp);
        ret%=mod;
        if(flag) return 0;
      }
      ins[x][res]=0;
      if(x==n&&res==0) ret++;
      return ret%mod;
    }
    void init(){
      memset(head,0,sizeof(head));
      memset(e,0,sizeof(e));
      ecnt=0;flag=0;
      memset(head2,0,sizeof(head2));
      memset(e2,0,sizeof(e2));
      ecnt2=0;
      memset(ins,0,sizeof(ins));
      memset(f,-1,sizeof(f));
    }
    
    int solve(){
      init();
      n=rd();m=rd();num=rd();mod=rd();
      int x,y,w;
      for(int i=1;i<=m;i++){
        x=rd();y=rd();w=rd();
        add(y,x,w);add2(x,y,w);
      }
      dij();
      long long ans=0;
      for(int i=0;i<=num;i++) {
        memset(ins,0,sizeof(ins));
        ans+=1ll*dfs(1,i)%mod;
        ans%=mod;//!
      }
      if(flag) return puts("-1"),0;
      printf("%lld
    ",ans);
    }
    
    int main(){
      int T;
      T=rd();
      while(T--) solve();
    
      return 0;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9363189.html

  • 相关阅读:
    Codeforces 1265A Beautiful String
    1039 Course List for Student (25)
    1038 Recover the Smallest Number (30)
    1037 Magic Coupon (25)
    1024 Palindromic Number (25)
    1051 Pop Sequence (25)
    1019 General Palindromic Number (20)
    1031 Hello World for U (20)
    1012 The Best Rank (25)
    1011 World Cup Betting (20)
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9363189.html
Copyright © 2011-2022 走看看