NOIP2017 Day1T3

最短路+topsort+dp

求出1到所有点的单源最短路。

所有edge(x,y)满足dis[x]+w[e]dis[y],

则大于最短路的值不会减少。

设状态f[i][j]为到达i点时经过的长度为dis[i]+j(jk)的路径数.

因此对于一个节点可以扩展出其他k个新结点.

分别表示不同的距离(dis[x]~dis[x]+k).

这就是一个分层图,同层的点之间进行转移,或者向上层的点进行转移,不会向下层的点进行转移。

那么是在分层图上求路径总数。

自然 f[1][0]=1,

做topsort时进行dp转移。

topsort后

一个点没有deg,它的f之和值即为路径总数.

否则,它的路径总数为无穷.

统计sigma(f[n][0...k])。

总时间复杂度 O(T(mlogn+mk))

#include<stdio.h>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<queue>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
#define VIS(now) for(register int e=las[now];e;e=nxt[e])
#define pos(x,y) (x+(y)*n)
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
using std::priority_queue;
using std::pair;
using std::make_pair;
const int N=800011,M=1600011,inf=(1<<30);
priority_queue<pa>heap;
inline char nc(){
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int ret=0;char ch=nc();
    while(!isdigit(ch))ch=nc();
    while(isdigit(ch))ret=((ret+(ret<<2))<<1)+(ch^'0'),ch=nc();
    return ret;
}
int nxt[M],las[N],to[M],w[M],dis[N],vis[N],l[N*51],r[N*51],t[M*51],deg[N*51],f[N*51],que[N*51];
int tot,cnt,n,m,k,p,T,now,ans,head,tail;
inline void add(int x,int y,int z){
    nxt[++tot]=las[x];las[x]=tot;to[tot]=y;w[tot]=z;
}
inline void DJ(){
    int now;
    dis[1]=0;
    heap.push(mp(0,1));
    while(!heap.empty()){
        now=heap.top().second;
        heap.pop();
        if(vis[now])continue;
        vis[now]=1;
        VIS(now)
            if(dis[now]+w[e]<dis[to[e]]){
                dis[to[e]]=dis[now]+w[e];
                heap.push(mp(-dis[to[e]],to[e]));
            }
    }
}
int x,y,z;
int main(){
    T=read();
    die:;
    while(T--){
        ans=tot=cnt=0;
        n=read();m=read();k=read();p=read();
        FOR(i,1,n)las[i]=0,dis[i]=inf,vis[i]=0;
        FOR(i,1,pos(n,k))f[i]=0,deg[i]=0;
        f[1]=1;
        while(m--)x=read(),y=read(),z=read(),add(x,y,z);
        DJ();
        FOR(i,1,n)
            FOR(j,0,k){
                l[pos(i,j)]=cnt+1;
                VIS(i)
                    if(j+dis[i]+w[e]-dis[to[e]]<=k)
                        ++deg[t[++cnt]=pos(to[e],j+dis[i]+w[e]-dis[to[e]])];
                r[pos(i,j)]=cnt;
            }
        head=1,tail=0;
        FOR(i,1,pos(n,k))
            if(!deg[i])
                que[++tail]=i;
        while(head<=tail){
            now=que[head++];
            FOR(i,l[now],r[now]){
                --deg[t[i]];
                f[t[i]]+=f[now];
                if(f[t[i]]>=p)f[t[i]]-=p;
                if(!deg[t[i]])que[++tail]=t[i];
            }
        }
        FOR(i,0,k){
            if(deg[pos(n,i)]){
                puts("-1");
                goto die;
            }
            ans+=f[pos(n,i)];
            if(ans>=p)ans-=p;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

posted @ 2017-11-25 21:54  Stump  阅读(221)  评论(0编辑  收藏  举报