洛谷 3953 NOIP2017提高组Day1 T3 逛公园

【题解】

  先建反向图,用dijkstra跑出每个点到n的最短距离dis[i]

  设f[u][k]表示dis(u,n)<=mindis(u,n)+k的方案数。对于边e(u,v,w),走了这条边的话需要多走的距离就是这条边的边权-原来u,v之间的距离,即w-(dis[u]-dis[v])

  那么转移就是f[u][k]=sigma( f[v][k-w+(dis[u]-dis[v])] ),记忆化搜索非常好写。

  判无数解的话记录当前状态是否在栈中就可以了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 #define rg register
 6 #define N 200010
 7 using namespace std;
 8 int T,n,m,k,p,tot,last[N],dis[N],pos[N],f[N][60];
 9 bool in[N][60];
10 struct edge{int to,pre,dis;}e[N];
11 struct heap{int p,d;}h[N];
12 struct rec{int u,v,w;}r[N];
13 inline int read(){
14     int k=0,f=1; char c=getchar();
15     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
16     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
17     return k*f;
18 }
19 inline void MOD(int &k){if(k>=p) k-=p;}
20 inline void up(int x){
21     int fa;
22     while((fa=x>>1)&&h[fa].d>h[x].d) swap(h[x],h[fa]),swap(pos[h[x].p],pos[h[fa].p]),x=fa;
23 }
24 inline void down(int x){
25     int son;
26     while((son=x<<1)<=tot){
27         if(h[son+1].d<h[son].d&&son<tot) son++;
28         if(h[son].d<h[x].d) swap(h[x],h[son]),swap(pos[h[x].p],pos[h[son].p]),x=son;
29         else return;
30     }
31 }
32 inline void dijkstra(int x){
33     for(rg int i=1;i<=n;i++) dis[i]=1e9;
34     h[pos[x]=tot=1]=(heap){x,dis[x]=0};
35     while(tot){
36         int now=h[1].p; pos[h[tot].p]=1; h[1]=h[tot--]; if(tot) down(1);
37         for(rg int i=last[now],to;i;i=e[i].pre)if(dis[to=e[i].to]>dis[now]+e[i].dis){
38             dis[to]=dis[now]+e[i].dis;
39             if(!pos[to]) h[pos[to]=++tot]=(heap){to,dis[to]};
40             else h[pos[to]].d=dis[to];
41             up(pos[to]);
42         }
43     }
44 }
45 int dfs(int x,int d){
46     if(in[x][d]) return -1;
47     if(f[x][d]) return f[x][d];
48     in[x][d]=1; f[x][d]=(x==n)?1:0;
49     for(rg int i=last[x],to,num;i;i=e[i].pre){
50         int tmp=-dis[x]+dis[to=e[i].to]+e[i].dis;
51         if(tmp<=d){
52             if((num=dfs(to,d-tmp))==-1) return -1;
53             MOD(f[x][d]+=num); 
54         }
55     }
56     return in[x][d]=0,f[x][d];
57 }
58 inline void Pre(){
59     memset(in,0,sizeof(in));
60     memset(last,0,sizeof(last));
61     memset(pos,0,sizeof(pos));
62     memset(f,0,sizeof(f));
63     tot=0;
64 }
65 int main(){
66     T=read();
67     while(T--){
68         Pre();
69         n=read(); m=read(); k=read(); p=read();
70         for(rg int i=1,u,v;i<=m;i++){
71             r[i].u=u=read(); r[i].v=v=read();
72             e[++tot]=(edge){u,last[v],r[i].w=read()}; last[v]=tot;
73         }
74         dijkstra(n);
75         memset(last,0,sizeof(last)); tot=0;
76         for(rg int i=1;i<=m;i++){
77             int u=r[i].u,v=r[i].v;
78             e[++tot]=(edge){v,last[u],r[i].w}; last[u]=tot;
79         }
80         printf("%d\n",dfs(1,k));
81     }
82     return 0;
83 }

 

posted @ 2018-10-25 16:47  Driver_Lao  阅读(227)  评论(0编辑  收藏  举报