luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)
先跑一边dijkstra算出从1到i的最短距离dis[i]
然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数
答案就是$\sum\limits_{i=0}^{k}{(n,i)}$
考虑0环,如果我记搜的时候搜到了0环,那答案就是-1,可以先用tarjan处理一下0边 看看有哪些点在零环上
(其实也可以开个栈 做到(p,k)的时候看(p,k)是不是已经在栈中了 如果是那就是-1)
1 #include<bits/stdc++.h> 2 #define CLR(a,x) memset(a,x,sizeof(a)) 3 using namespace std; 4 typedef long long ll; 5 typedef pair<int,int> pa; 6 const int maxn=1e5+10,maxm=2e5+10,maxk=55; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 struct Edge{ 16 int b,l,ne; 17 }eg[maxm],neg[maxm]; 18 struct Node{ 19 int p,k,n; 20 Node(int a=0,int b=0,int c=0){p=a,k=b,n=c;} 21 }; 22 int egh[maxn],negh[maxn],ect,nect; 23 int dis[maxn],f[maxn][maxk]; 24 int dfn[maxn],tot,low[maxn],stk[maxn],sh; 25 int N,M,K,P; 26 bool in0[maxn],instk[maxn],flag[maxn]; 27 28 inline void adeg(int a,int b,int c){ 29 eg[++ect].b=b,eg[ect].l=c,eg[ect].ne=egh[a],egh[a]=ect; 30 neg[++nect].b=a,neg[nect].l=c,neg[nect].ne=negh[b],negh[b]=nect; 31 } 32 33 void tarjan(int x){ 34 dfn[x]=low[x]=++tot,instk[x]=1,stk[++sh]=x; 35 for(int i=egh[x];i;i=eg[i].ne){ 36 if(eg[i].l) continue; 37 int b=eg[i].b; 38 if(!dfn[b]) tarjan(b),low[x]=min(low[x],low[b]); 39 else if(instk[b]) low[x]=min(low[x],dfn[b]); 40 } 41 if(dfn[x]==low[x]){ 42 int n=0; 43 for(int i=sh;stk[i]!=x;i--) n++; 44 while(1){ 45 instk[stk[sh]]=0; 46 in0[stk[sh]]=n>0; 47 if(stk[sh--]==x) break; 48 } 49 } 50 } 51 52 priority_queue<pa,vector<pa>,greater<pa> > q; 53 inline void dijkstra(){ 54 while(!q.empty()) q.pop(); 55 CLR(flag,0);CLR(dis,63);dis[1]=0; 56 q.push(make_pair(0,1)); 57 while(!q.empty()){ 58 int p=q.top().second;q.pop(); 59 if(flag[p]) continue; 60 flag[p]=1; 61 for(int i=egh[p];i;i=eg[i].ne){ 62 int b=eg[i].b; 63 if(dis[b]>dis[p]+eg[i].l){ 64 dis[b]=dis[p]+eg[i].l; 65 q.push(make_pair(dis[b],b)); 66 } 67 } 68 } 69 } 70 71 inline int solve(int x,int y){ 72 // if(f[x][y]>=0) printf("get%d %d %d\n",x,y,f[x][y]); 73 if(y<0||y>K) return 0; 74 if(in0[x]) return -1; 75 if(f[x][y]>=0) return f[x][y]; 76 f[x][y]=0; 77 for(int i=negh[x];i;i=neg[i].ne){ 78 int b=neg[i].b; 79 int re=solve(b,dis[x]-dis[b]+y-neg[i].l); 80 if(re==-1) return -1; 81 f[x][y]+=re,f[x][y]%=P; 82 } 83 return f[x][y]; 84 } 85 86 int main(){ 87 int i,j,k; 88 for(int T=rd();T;T--){ 89 N=rd(),M=rd(),K=rd(),P=rd(); 90 CLR(egh,0);ect=0; 91 CLR(negh,0);nect=0; 92 for(i=1;i<=M;i++){ 93 int a=rd(),b=rd(),c=rd(); 94 adeg(a,b,c); 95 } 96 CLR(dfn,0);CLR(instk,0);tot=0;CLR(in0,0); 97 for(i=1;i<=N;i++) 98 if(!dfn[i]) tarjan(i); 99 dijkstra(); 100 CLR(f,-1); 101 f[1][0]=1;int ans=0; 102 for(i=0;i<=K;i++) 103 ans+=solve(N,i),ans%=P; 104 printf("%d\n",ans<0?-1:ans); 105 } 106 107 return 0; 108 }