[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 <bits/stdc++.h>
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 <node> 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]<dis[to[i]])
        {
            dis[to[i]]=dis[t.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]<pdis[pre[i]])
        {
            pdis[pre[i]]=pdis[t.x]+len[i];
            heap.push((node){pre[i],pdis[pre[i]]});
        }
    }
    //for (int i=1;i<=n;++i) cout<<dis[i]<<' ';cout<<endl;
    //for (int i=1;i<=n;++i) cout<<pdis[i]<<' ';cout<<endl;
    ling=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<<"========="<<endl;for (int i=1;i<=num;++i) cout<<pre[i]<<' '<<to[i]<<' '<<len[i]<<endl;cout<<"=========="<<endl;
    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 (st<ed)
    {
        int 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<<ans<<endl;
}
int main()
{
    //freopen("park.in","r",stdin);
    //freopen("park.out","w",stdout);
    int T;
    cin>>T;
    while (T--) solve();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章