[NOIP2017][luogu3953]逛公园

大意:给定有向图G,求1->n的长度<=最短距离+K的路径方案数
先求起点到每个点和每个点到终点的最短路,排除掉不可能到达的点防止其干扰(dis[i]+pdis[i]>dis[n]+K)
然后每条边的边权更新为len[x->y]+dis[x]-dis[y] (走这条边浪费的时间)
现在只需要统计浪费的时间不超过K的方案
长度为0的边用拓扑序转移,长度>0的直接转移……(dp[x][j]->dp[y][j+len])
求拓扑序的时候可以顺便判一下0环
代码极烂……Orz w_yqts

#include 
using namespace std;
#define inf 1000000000
#define N 500005
int ins[N];
int tot[N][60],q[N],inq[N],st,ed,dian[N],rd[N],ans;
int num,pre[N],to[N],Next[N],Next1[N],head[N],tail[N],len[N];
int dis[N],pdis[N],flag[N];
int n,m,K,p,ling,x,y,z;
inline void init()
{
    num=0;
    for (int i=1;i<=n;++i) head[i]=0,tail[i]=0,dis[i]=inf,pdis[i]=inf;
}
inline void add(int x,int y,int t)
{
    ++num;
    pre[num]=x;
    to[num]=y;
    Next[num]=head[x];
    head[x]=num;
    Next1[num]=tail[y];
    tail[y]=num;
    len[num]=t;
}
struct node
{
    int x,s;
}t;
bool operator > (node x,node y)
{
    return x.s<y.s;
}
bool operator < (node x,node y)
{
    return x.s>y.s;
}
priority_queue  heap;
inline int read()
{
    char ch=getchar();
    int x=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while ('0'<=ch && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x;
}
inline void solve()
{
    scanf("%d%d%d%d",&n,&m,&K,&p);
    init();
    for (int i=1;i<=m;++i)
    {
        x=read(),y=read(),z=read();
        add(x,y,z);
    }
    dis[1]=0;
    heap.push((node){1,0});
    for (int i=1;i<=n;++i) flag[i]=1;
    while (!heap.empty())
    {
        t=heap.top();heap.pop();
        while (!flag[t.x] && !heap.empty()) t=heap.top(),heap.pop();
        if (!flag[t.x]) break;
        flag[t.x]=0;
        for (int i=head[t.x];i;i=Next[i])
        if (dis[t.x]+len[i]x]+len[i];
            heap.push((node){to[i],dis[to[i]]});
        }
    }
    pdis[n]=0;
    heap.push((node){n,0});
    for (int i=1;i<=n;++i) flag[i]=1;
    while (!heap.empty())
    {
        t=heap.top();heap.pop();
        while (!flag[t.x] && !heap.empty()) t=heap.top(),heap.pop();
        if (!flag[t.x]) break;
        flag[t.x]=0;
        for (int i=tail[t.x];i;i=Next1[i])
        if (pdis[t.x]+len[i]x]+len[i];
            heap.push((node){pre[i],pdis[pre[i]]});
        }
    }
    //for (int i=1;i<=n;++i) cout<' ';cout<//for (int i=1;i<=n;++i) cout<' ';cout<0;
    for (int i=1;i<=n;++i) dian[i]=flag[i]=1,rd[i]=0;
    for (int i=1;i<=num;++i) len[i]=len[i]+dis[pre[i]]-dis[to[i]];
    //cout<<"========="<for (int i=1;i<=num;++i) cout<' '<' '<"=========="<for (int i=1;i<=n;++i) if (dis[i]+pdis[i]>dis[n]+K) dian[i]=0;
    for (int i=1;i<=num;++i) if (dian[to[i]] && len[i]==0 && dian[pre[i]]) flag[pre[i]]=0,++rd[to[i]];
    st=0,ed=0;
    for (int i=1;i<=n;++i) if (!rd[i] && dian[i] && !flag[i]) q[++ed]=i;
    while (stint x=q[++st];
        for (int i=head[x];i;i=Next[i])
        if (len[i]==0 && dian[to[i]])
        {
            int y=to[i];
            --rd[y];
            if (!rd[y]) q[++ed]=y;
        }
    }
    int led=ed;
    for (int i=1;i<=n;++i) if (rd[i]) {ling=1;break;}
    if (ling) {puts("-1");return;}
    for (int j=0;j<=K;++j) for (int i=1;i<=n;++i) tot[i][j]=0;
    tot[1][0]=1;
    ans=0;
    for (int j=0;j<=K;++j)
    {
        for (int i=1;i<=led;++i)
        {
            int x=q[i];
            if (!dian[x] || !tot[x][j]) continue;
            for (int k=head[x];k;k=Next[k])
            if (j+len[k]<=K && !len[k])
            {
                tot[to[k]][j+len[k]]=(tot[to[k]][j+len[k]]+tot[x][j])%p;
            }
        }
        for (int i=1;i<=num;++i)
        if (len[i] && j+len[i]<=K)
        {
            tot[to[i]][j+len[i]]=(tot[to[i]][j+len[i]]+tot[pre[i]][j])%p;
        }
    }
    for (int i=0;i<=K;++i) ans=(ans+tot[n][i])%p;
    cout<int main()
{
    //freopen("park.in","r",stdin);
    //freopen("park.out","w",stdout);
    int T;
    cin>>T;
    while (T--) solve();
}

你可能感兴趣的:(dp,拓扑,图,noip,2017)