[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\n",ans);
}

int main(){
  int T;
  T=rd();
  while(T--) solve();

  return 0;
}

猜你喜欢

转载自www.cnblogs.com/ghostcai/p/9363189.html