zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    eclipse中在线添加TestNG插件步骤(需联网)
    [IOI2008] Type Printer 打印机
    P2765 魔术球问题
    [HNOI2004]敲砖块
    P3931 SAC E#1
    [WC2005]友好的生物
    P1357 花园
    [SDOI2016]征途
    [APIO2014]序列分割
    [HNOI2008]玩具装箱TOY
  • 原文地址:https://www.cnblogs.com/Stump/p/7896595.html
Copyright © 2011-2022 走看看