• [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

  • 相关阅读:
    Java ConcurrentModificationException 异常分析与解决方案
    android studio 怎么做屏幕适配?
    java Class.getSimpleName() 的用法
    LeetCode——Remove Element
    用WidgeDuino创建一个SCADA(监控与数据採集)系统
    【Oracle】OCR的备份和恢复之导出导入
    Java大数类介绍
    POJ 1113 Wall 凸包
    OPENCV中滑动条的使用
    Android
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9363189.html
Copyright © 2020-2023  润新知