并不对劲的noip2017d1t3

因为A掉了d1t1,十分开心,把d1t3的代码调出来了。

一般情况下,noip每一天总有一道dp题,然而d1前两道题都不是,再看看第三题的数据范围,就能大概猜出是dp了。

这道题和最短路计数看上去很像。回想一下最短路计数的解法,大概是按照bfs序进行dp,dp[u]表示到节点u的条数。对于这道题而言,求的不是最短路条数而是长度不超过最短路+k的路径条数,那么就可以用dp[u][j]表示到节点u路径长度等于j的路径数。

至于如何转移,用dis[x]表示x到1的最短路长度,则当dis[u]+w[k]+j-dis[x]<=k有dp[x][dis[u]+w[k]+j-dis[vv]]+=dp[u][j]。

至于转移顺序,想到最短路计数是bfs序,而这道题有边权,那么就是dijkstra序(<-瞎编的词),其实就是dis[x]由小到大的顺序。

至于0边,需要建一个新图,图中只有0边。用一个拓扑排序找出0环,若环上存在点x满足1到x的距离+x到n的距离<=1到n的距离+k,则这个环会被计数,输出-1。还有一点需要注意的是,当出现0边时,dp顺序不单单是dis[x]的顺序。当出现x--0-->y,显然是要先算dp[x]的。这是就需要用到之前算出的拓扑序,当两个点的dis相等时,先算拓扑序靠前的那个。

下面是代码,我略作修改,使它有可能RE。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define stnd struct node
#define nd node
#define oops operator
#define maxn 400010
#define maxm 800010
#define ll long long
using namespace std;
ll v[maxm],w[maxm],fir[maxn],nxt[maxm],cnt;//For roads.
ll fv[maxm],fw[maxm],ffir[maxn],fnxt[maxm],fcnt;//For froads.
ll tl,in[maxn],dep[maxn],ord[maxn],inq[maxn];//For topo sorting.
ll n,m,inf,t,dp[maxn][60],kkk,p;;//For counting.
ll dis[maxn],fdis[maxn];//For dijkstra.
bool fl,vis[maxn][60];
stnd
{
    ll x,y;
    bool oops <(const nd &zz)const
    {
        return y>zz.y;
    }
};
inline ll read()
{
    ll xx=0,ff=1;
    char ch=getchar();
    while(isdigit(ch)==0 && ch!='-')ch=getchar();
    if(ch=='-')ff=-1,ch=getchar();
    while(isdigit(ch))xx=xx*10+ch-'0',ch=getchar();
    return xx*ff;
}
void addedge(ll u1,ll v1,ll w1)
{
    v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;
    fv[fcnt]=u1,fw[fcnt]=w1,fnxt[fcnt]=ffir[v1],ffir[v1]=fcnt++;
}
void dj()
{
    memset(dis,0x7f,sizeof(dis));
    priority_queue<stnd>q;
    stnd tmp;
    tmp.x=1,tmp.y=0;
    dis[1]=0;
    q.push(tmp);
    while(!q.empty())
    {
        ll u=q.top().x,du=q.top().y;q.pop();
        if(dis[u]<du)continue;
        for(ll k=fir[u];k!=-1;k=nxt[k])
        {
            ll vv=v[k];
            if(dis[vv]>dis[u]+w[k])
            {
                dis[vv]=dis[u]+w[k];
                tmp.x=vv,tmp.y=dis[vv];
                q.push(tmp);
            }
        }
    }
}
void fdj()
{
    memset(fdis,0x7f,sizeof(fdis));
    priority_queue<stnd>q;
    stnd tmp;
    tmp.x=n,tmp.y=0;
    fdis[n]=0;
    q.push(tmp);
    while(!q.empty())
    {
        ll u=q.top().x,du=q.top().y;q.pop();
        if(fdis[u]<du)continue;
        for(ll k=ffir[u];k!=-1;k=fnxt[k])
        {
            ll vv=fv[k];
            if(fdis[vv]>fdis[u]+fw[k])
            {
                fdis[vv]=fdis[u]+fw[k];
                tmp.x=vv,tmp.y=fdis[vv];
                q.push(tmp);
            }
        }
    }
}
void topoo(ll xx)
{
    inq[xx]=1;
    ord[tl++]=xx;
    for(ll k=fir[xx];k!=-1;k=nxt[k])
    {
        if(w[k]!=0)continue;
        ll vv=v[k];
        in[vv]--;
        if(in[vv]==0)
            topoo(vv);
    }
    return;
}
void topo()
{
    tl=1;
    memset(inq,0,sizeof(inq));
    memset(in,0,sizeof(in));
    for(ll i=0;i<m;i++)
        if(w[i]==0)in[v[i]]++;
    for(ll i=1;i<=n;i++)
        if(inq[i]==0 && in[i]==0)
            topoo(i);
    for(ll i=1;i<=n;i++)
    {
        if(in[i]!=0 && 
        dis[i]+fdis[i]<=dis[n]+kkk)
            fl=1;
    }
}
bool dfs(int u,int j)
{
    if(vis[u][j])return 1;
    if(~dp[u][j])return 0;
    vis[u][j]=1;
    if(u==n)dp[u][j]=1;
    else dp[u][j]=0;
    for(int k=fir[u];k!=-1;k=nxt[k])
    {
        int vv=v[k],tt=dis[u]-dis[vv]+w[k]+j;
        if(tt<=kkk && 
        dis[u]+j+w[k]+fdis[vv]<=kkk+fdis[1])
        {
            if(dfs(vv,tt))return 1;
            dp[u][j]+=dp[vv][tt];
            dp[u][j]%=p; 
        }
    }
    vis[u][j]=0;
    return 0;
}
int main()
{
    t=read();
    while(t--)
    {
        cnt=fcnt=fl=0;
        n=read(),m=read(),kkk=read(),p=read();
        memset(fir,-1,sizeof(fir));
        memset(ffir,-1,sizeof(ffir));
        memset(dp,-1,sizeof(dp));
        memset(vis,0,sizeof(vis));
        for(ll i=1;i<=m;i++)
        {
            ll x=read(),y=read(),z=read();
            addedge(x,y,z);
        }
        dj();
        fdj();
        topo();
        if(fl)cout<<-1;
        else
        {
            dfs(1,0);
            cout<<dp[1][0];
        }
        cout<<endl;
    }
    return 0;
}
View Code

 

posted @ 2017-12-07 14:12  echo6342  阅读(258)  评论(0编辑  收藏  举报