1. 程式人生 > >P3953 NOIP2017 d1t3 逛公園

P3953 NOIP2017 d1t3 逛公園

ext lis 數據 getc sample badge 最短路 喜歡 。。

題目描述

策策同學特別喜歡逛公園。公園可以看成一張NN 個點MM 條邊構成的有向圖,且沒有 自環和重邊。其中1號點是公園的入口,NN 號點是公園的出口,每條邊有一個非負權值, 代表策策經過這條邊所要花的時間。

策策每天都會去逛公園,他總是從1號點進去,從NN 號點出來。

策策喜歡新鮮的事物,它不希望有兩天逛公園的路線完全一樣,同時策策還是一個 特別熱愛學習的好孩子,它不希望每天在逛公園這件事上花費太多的時間。如果1號點 到NN 號點的最短路長為dd ,那麽策策只會喜歡長度不超過d + Kd+K 的路線。

策策同學想知道總共有多少條滿足條件的路線,你能幫幫它嗎?

為避免輸出過大,答案對PP 取模。

如果有無窮多條合法的路線,請輸出−1。

輸入輸出格式

輸入格式:

第一行包含一個整數 TT , 代表數據組數。

接下來TT 組數據,對於每組數據: 第一行包含四個整數 N,M,K,PN,M,K,P ,每兩個整數之間用一個空格隔開。

接下來MM 行,每行三個整數a_i,b_i,c_iai?,bi?,ci? ,代表編號為a_i,b_iai?,bi? 的點之間有一條權值為 c_ici? 的有向邊,每兩個整數之間用一個空格隔開。

輸出格式:

輸出文件包含 TT 行,每行一個整數代表答案。

輸入輸出樣例

輸入樣例#1: 復制
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
輸出樣例#1: 復制
3
-1

說明

【樣例解釋1】

對於第一組數據,最短路為 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 為 3 條合法路徑。

【測試數據與約定】

對於不同的測試點,我們約定各種參數的規模不會超過如下

測試點編號  TT    NN    MM    KK    是否有0邊
1 5 5 10 0
2 5 1000 2000 0
3 5 1000 2000 50
4 5 1000 2000 50
5 5 1000 2000 50
6 5 1000 2000 50
7 5 100000 200000 0
8 3 100000 200000 50
9 3 100000 200000 50
10 3 100000 200000 50

對於 100%的數據, 1 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001P109,1ai?,bi?N,0ci?1000 。

數據保證:至少存在一條合法的路線。

只有60的記憶化搜索。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<complex>
#include<queue>
#define N    100000+5
#define K    50+3
#define INF  0x7FFFFFFF
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
     while(s>9 || s<0){if(s==-)f=-1;s=getchar();}
     while(s<=9 && s>=0){x=x*10+s-0;s=getchar();}
     return x*f;
}
struct edge{int to,next,v;}a[N],re[N];
int n,m,k,p,cnt,cnt1,head[N],headre[N],v[N],ans[N][K],vis[N][K],d[N],alive[N];
void add(int x,int y,int v)
{
    a[++cnt].to=y;a[cnt].v=v;
    a[cnt].next=head[x];head[x]=cnt;
}
void addre(int x,int y,int v)
{
    re[++cnt1].to=y;re[cnt1].v=v;
    re[cnt1].next=headre[x];headre[x]=cnt1;
}

int dfs(int x,int b)
{
    if(b<0)return 0;
    if(vis[x][b]==1)return -INF;
    if(ans[x][b]!=-1)return ans[x][b];
    vis[x][b]=1;
    int key=0;
    if(x==n)key++;
    for(int i=head[x];i;i=a[i].next)
        if(alive[a[i].to])
        {
            int v=a[i].to;
            int delta=a[i].v-(d[v]-d[x]);
            int w=dfs(v,b-delta);
            if(w==-INF)return -INF;
            else key=(key+w)%p;
        }
    ans[x][b]=key%p;
    vis[x][b]=0;
    return key;
}

void spfa()
{
    queue<int>q;
    q.push(1);v[1]=1;
    d[1]=0;
    while(!q.empty())
    {
        int h=q.front();q.pop();v[h]=0;
        for(int i=head[h];i;i=a[i].next)
        {
            int x=a[i].to;
            if(d[h]+a[i].v<d[x])
            {
                d[x]=d[h]+a[i].v;
                if(!v[h])
                q.push(x);
            }
        }
    }
}
void da()
{
    queue<int>q;
    q.push(n);alive[n]=1;
    while(!q.empty())
    {
        int h=q.front();q.pop();
        for(int i=headre[h];i;i=re[i].next)
        {
            int x=re[i].to;
            if(!alive[x]){alive[x]=1;q.push(x);}
        }
    }
}
void init()
{
    for(int i=1;i<=n;i++)
    {
        a[i].to=a[i].next=a[i].v=0;
        re[i].to=re[i].next=re[i].v=0;
        head[i]=headre[i]=v[i]=d[i]=alive[i]=0;
        for(int l=0;l<=k;l++)
        {
            ans[i][l]=-1;
            vis[i][l]=0;
        }
    }
}
int main()
{
    int t;t=read();
    while(t--)
    {
        n=read(),m=read(),k=read(),p=read();
        init();
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            a=read(),b=read(),c=read();
            add(a,b,c);addre(b,a,c);
        }
        for(int i=1;i<=n;i++)d[i]=INF;
        spfa(); 
        da();
        
        //for(int i=1;i<=n;i++)cout<<d[i]<<‘ ‘;
        
        int z=dfs(1,k);
        if(z==-INF)printf("-1\n");else printf("%d\n",z%p);
    }
    return 0;
}

P3953 NOIP2017 d1t3 逛公園