[NOIP2017] 逛公园

[NOIP2017] 逛公园

题目大意:

给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条。
数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^5\)

题目解法

两个月后再看也不是太难,自己就能独立思考出来。
首先是判-1的问题,显然能产生-1的只有0环。
所以把0环都找出来,
然后检查一下\(dis[\)\(1\),环\(]\) + \(dis[\)环,\(n]\) 是否小于等于 \(dis[1,n]+K\)即可。
如果不是无限路径的话,也比较套路了。直接把距离扔到\(DP\)维数中肯定不现实。
所以设\(f[ u ][ d ]\)表示从1到u,长度为\(dis[1,u]\)+\(d\) 的路径有多少条。
我们假设\(u\) --> \(v\),\(d_u = rest'\) , \(d_v = rest\) , 那么有如下关系:
\[rest' + dis[1 , u ] + t[ i ].lg\ \ =\ \ rest + dis[1 , v]\]
转移:\(f[v][rest] = \sum f[ u ][rest']\) , 初值\(f[1][0] = 1\)
细节比较多 , 求 \(0\)环 判 -1 可以用\(Tarjan\)做,只走边权为0的边即可。
然后\(DP\)的时候转移顺序不好处理 , 所以记忆化搜索即可。

实现代码:

注:记忆化搜索倒着搜比较方便就倒着搜了。

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define os 55
#define _ 200005
#define INF 1000000007
using namespace std;

IL int gi(){
    RG int data = 0 , m = 1; RG char ch = 0;
    while(ch != '-' && (ch < '0' || ch > '9') ) ch = getchar();
    if( ch == '-' ) { ch = getchar(); m = 0; }
    while(ch >= '0' && ch <= '9'){data = (data << 1) + (data << 3) + (ch ^ 48); ch = getchar();}
    return ( m ) ? data : -data;
} 

int Case,N,M,K,P,zero_res,oo,top,cnt,ans,init[_];
int dis[_][2],dp[_][os],dfn[_],low[_],stk[_],tmp[_],hd[_];
struct Road{int to , next , w ; }t[2*_][ 2 ] ; int head[ _ ][ 2 ];
bool vis[_]; queue<int>Q;

IL void spfa(RG int S , RG int id){
    for(RG int i = 1; i <= N; i ++)dis[ i ][id] = INF ;
    vis[ S ] = true; Q.push( S ) ; dis[ S ][id] = 0;
    while(!Q.empty()){
        RG int u = Q.front(); Q.pop();
        for(RG int i = head[ u ][id] ; i ; i = t[ i ][id].next){
            RG int v = t[ i ][id].to ;
            if(dis[ v ][id] > dis[ u ][id] + t[ i ][id].w){
                dis[ v ][id] = dis[ u ][id] + t[ i ][id].w ;
                if(! vis[ v ] ) Q.push( v ) , vis[ v ] = true;
            }
        }vis[ u ] = false;
    }return;
}

IL void Tarjan( RG int u ){
    stk[ ++ top ] = u;
    dfn[ u ] = low[ u ] = ++ oo ; init[ u ] = true;
    for(RG int i = head[ u ][0] ; i ; i = t[ i ][0].next){
        if(t[ i ][0].w != 0)continue; RG int v = t[ i ][0].to;
        if( !dfn[ v ] )
            Tarjan( v ) , low[ u ] = min(low[ u ] , low[ v ]) ;
        else if(init[ v ])low[ u ] = min(low[ u ] , dfn[ v ]) ;
    }
    if(low[ u ] == dfn[ u ]){
        RG int e , ct = 0;
        while(1){
            e = stk[ top ] ; top --;
            init[e] = false; tmp[ ++ct ] = e;
            if(e == u || !top) break;
        }
        if(ct >= 2)
            zero_res = min( dis[ u ][ 0 ] + dis[ u ][ 1 ] , zero_res) ;
    }return;
}

IL int DP( RG int u , RG int rest ) {
    if( dp[ u ][ rest ] )return dp[ u ][ rest ] ;
    for(RG int i = head[ u ][ 1 ] ; i ; i = t[ i ][ 1 ].next){
        RG int v = t[ i ][ 1 ].to , d;
        d = rest + dis[ u ][ 0 ] - dis[ v ][ 0 ] - t[ i ][ 1 ].w ;
        if( d < 0 )continue;
        dp[ u ][ rest ] = ( dp[ u ][ rest ] + DP( v , d ) ) % P;
    }return dp[ u ][ rest ] ;
}
//v-->u : rest' + dis[v][0] + t[i].w = rest + dis[u][0]

int main(){
    freopen("2017park.in" , "r" , stdin);
    freopen("2017park.out" , "w" , stdout);
    Case = gi();
    while(Case -- ){

        N = gi(); M = gi(); K = gi(); P = gi();
        for(RG int i = 1; i <= N; i ++)head[ i ][ 0 ] = 0;
        for(RG int i = 1; i <= N; i ++)head[ i ][ 1 ] = 0;
        for(RG int i = 1; i <= N; i ++)dfn[ i ] = low[ i ] = 0;

        cnt = 0;
        for(RG int i = 1 , u , v , c; i <= M; i ++){
            u = gi(); v = gi(); c = gi(); ++ cnt ;
            t[ cnt ][ 0 ] = ( Road ) { v , head[ u ][ 0 ] , c } ;
            head[ u ][ 0 ] = cnt ;
            t[ cnt ][ 1 ] = ( Road ) { u , head[ v ][ 1 ] , c } ;
            head[ v ][ 1 ] = cnt ;
            //0 : u --> v (oder)  // 1 : v --> u (dder)
        }

        spfa(1 , 0) ; spfa(N , 1) ;
        zero_res = INF ;
        for(RG int i = 1; i <= N ; i ++) if( ! dfn[ i ] ) Tarjan( i ) ;

        if(zero_res <= dis[ N ][ 0 ] + K){ puts("-1") ; continue; }
        for(RG int i = 1; i <= N; i ++)
            for(RG int j = 0; j <= K; j ++)
                dp[ i ][ j ] = 0;
        dp[ 1 ][ 0 ] = 1;  ans = 0;
        for(RG int delta = 0; delta <= K; delta ++)
            ans = ( ans + DP( N , delta ) ) % P;
        cout << ans << endl;

    }return 0;
}

原文地址:https://www.cnblogs.com/GuessYCB/p/8463483.html

时间: 2024-11-05 22:54:48

[NOIP2017] 逛公园的相关文章

【比赛】NOIP2017 逛公园

考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在满足题目要求的路径上,那么这条路径就可以不停地走,于是就-1了. 如何判有没有零环呢? 机械化地两遍不同方向的SPFA,就知道某个点在不在最短路上,以此建一个最短路图,在最短路图上找零环.于是就拓扑啦.稍加判断就解决了整个题目最关键的-1. 接下来就是DP了,设f[i][j]表示走到i点,走过路程已

Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线. 策策

P3953 NOIP2017 d1t3 逛公园

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN 个点MM 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN 号点的最短路长为dd ,那么策策只会喜欢长度不超过d + Kd+K 

luogu 3953 逛公园

noip2017 D1T3 逛公园 某zz选手看到数据范围直接就最短路计数了,结果写错了爆零 题目大意: N个点M条边构成的有向图,且没有自环和重边.其中1号点是起点,N号点是公园的终点,每条边有一个非负权值, 代表经过这条边所要花的时间 如果1号点到N号点的最短路长为d,那么策策只选择长度不超过d + K的路线 求总共有多少条满足条件的路线 为避免输出过大,答案对P取模. 如果有无穷多条合法的路线,请输出?1 思路: 首先需要求出最短路用spfa 然后我们dfs的时候dp 具体见注释 1 #i

Luogu P3953 逛公园(最短路+记忆化搜索)

P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从 \(1\) 号点进去,从 \(N\) 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果 \(

TYVJ1427 小白逛公园

P1427 小白逛公园 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了.    一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的一些公园玩.小白当然希望选出的公园的分数总和尽量高咯

线段树--小白逛公园nkoj1316

小白逛公园 Time Limit:20000MS  Memory Limit:65536K Case Time Limit:2000MS Description 小新经常陪小白去公园玩,也就是所谓的遛狗啦-在小新家附近有一条"公园路",路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的

NOIP2017D1T3逛公园——哎呦!

#include<cstdio> #include<cstring> #define MXN 100001 #define MXM 200001 #define MXK 51 int afst[MXM],anxt[MXM],av[MXM],aw[MXM]; int bfst[MXM],bnxt[MXM],bv[MXM],bw[MXM]; int dis[MXN],queue[10*MXN]; int f[MXN][MXK],vis[MXN][MXK]; int n,m,k,p,t,

[NOIp 2017]逛公园

Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从$N$号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到$N$号点的最短路长为$d$,那么策策只会喜欢长度不超过$d