题目分析:

首先考虑无数条的情况。出现这种情况一定是一条合法路径经过了$ 0 $环中的点。那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离。加起来若离最短路径不超过$ k $则输出$ -1 $,否则这些点必定不被经过,接着dp后效性消失。由于每条边转移了$ k $次它的起点到终点的状态,所以总时间复杂度为$ O(n+mk) $,可以通过所有数据。

代码:

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
using namespace std; typedef pair<int,int> pr; const int maxn = ; int n,m,k,p;
vector<pair<int,int> > g[maxn],rg[maxn];
vector <int> ng[maxn]; int dfn[maxn],low[maxn],instack[maxn],scc[maxn],cl;
int f[maxn][],arr[maxn][];
stack <int> sta; void init(){
memset(dfn,,sizeof(dfn));
memset(arr,,sizeof(arr));
memset(low,,sizeof(low));
memset(instack,,sizeof(instack));
memset(scc,,sizeof(scc));
memset(f,,sizeof(f));
cl = ;
} void tarjan(int now){
low[now] = dfn[now] = ++cl;
sta.push(now);
for(int i=;i<ng[now].size();i++){
int k = ng[now][i]; if(instack[k]) continue;
if(dfn[k]) { low[now] = min(low[now],dfn[k]); }
else{ tarjan(k); low[now] = min(low[now],low[k]); }
}
if(low[now] == dfn[now]){
stack<int> tpp;int num = ;
while(true){
int tp = sta.top();sta.pop();tpp.push(tp);num++;
instack[tp] = ; scc[tp]=;
if(now == tp) break;
}
if(num == ) scc[tpp.top()] = ;
}
} void read(){
scanf("%d%d%d%d",&n,&m,&k,&p);
for(int i=;i<=n;i++) g[i].clear();
for(int j=;j<=n;j++) ng[j].clear();
for(int j=;j<=n;j++) rg[j].clear();
for(int i=;i<=m;i++){
int u,v,w; scanf("%d%d%d",&u,&v,&w);
g[u].push_back(make_pair(v,w));
rg[v].push_back(make_pair(u,w));
if(w == ) ng[u].push_back(v);
}
} int res;
int d[maxn][];
priority_queue<pr,vector<pr>,greater<pr> > pq;
void solve_dist(){
memset(d,0x3f,sizeof(d));
pq.push(make_pair(,));
while(!pq.empty()){
pair<int,int> tp = pq.top();pq.pop();
if(d[tp.second][] > 1e9) d[tp.second][] = tp.first;
else continue;
for(int j=;j<g[tp.second].size();j++){
int nxt = g[tp.second][j].first,data = g[tp.second][j].second;
data += d[tp.second][];
if(data > d[nxt][]) continue;
pq.push(make_pair(data,nxt));
}
}
res = d[n][];
pq.push(make_pair(,n));
while(!pq.empty()){
pair<int,int> tp = pq.top();pq.pop();
if(d[tp.second][] > 1e9) d[tp.second][] = tp.first;
else continue;
for(int j=;j<rg[tp.second].size();j++){
int nxt = rg[tp.second][j].first,data = rg[tp.second][j].second;
data += d[tp.second][];
if(data > d[nxt][]) continue;
pq.push(make_pair(data,nxt));
}
}
} void dfs(int now,int lw){
if(arr[now][lw]) return;
int nowd = d[now][]+lw;arr[now][lw] = ;
for(int j=;j<rg[now].size();j++){
int nxt = rg[now][j].first,data = rg[now][j].second;
if(scc[nxt])continue;
int nd = nowd-data; nd -= d[nxt][];
if(nd < ) continue;
if(nd > k) continue;
dfs(nxt,nd);
f[now][lw] += f[nxt][nd]; f[now][lw] %= p;
}
} void work(){
for(int i=;i<=n;i++) if(!dfn[i]) tarjan(i);
if(scc[]||scc[n]) {puts("-1");return;} solve_dist(); for(int i=;i<=n;i++)
if(scc[i]) if(d[i][]+d[i][]<=res+k){puts("-1");return;} f[][] = ;arr[][] = ;int ans = ;
for(int i=;i<=k;i++) {
dfs(n,i);ans += f[n][i]; ans %= p;
}
printf("%d\n",ans);
} int main(){
int t; scanf("%d",&t);
while(t--){ init(); read(); work(); }
return ;
}

[NOIP2017] 逛公园 【最短路】【强连通分量】的更多相关文章

  1. [NOIP2017]逛公园 最短路+拓扑排序+dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...

  2. [NOIP2017]逛公园 最短路图 拓扑序DP

    ---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ...

  3. [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)

    题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...

  4. [NOIP2017] 逛公园

    [NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...

  5. 【比赛】NOIP2017 逛公园

    考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在 ...

  6. 【题解】NOIP2017逛公园(DP)

    [题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n​节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...

  7. NOIP2017逛公园(dp+最短路)

    策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会 ...

  8. NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】

    题目描述 策策同学特别喜欢逛公园.公园可以看成一张NNN个点MMM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花 ...

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

    P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...

  10. [NOIP2017]逛公园 题解

    我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ...

随机推荐

  1. python之面向对象3

     面向对象介绍 一.面向对象和面向过程 面向过程:核心过程二字,过程即解决问题的步骤,就是先干什么后干什么 基于该思想写程序就好比在这是一条流水线,是一种机械式的思维方式 优点:复杂的过程流程化 缺点 ...

  2. centos7 安装phpmyadmin

    1.先安装epel,不然安装pgpmyadmin时会出现找不到包. yum install epel-release rpm -ivh http://rpms.famillecollet.com/en ...

  3. echarts各个配置项详细说明总结

    https://blog.csdn.net/sinat_34492035/article/details/70258557 https://blog.csdn.net/qq_34908167/arti ...

  4. stark组件之pop页面,按钮,url,页面

      1.Window open() 方法 2.admin的pop添加按钮 3.stark之pop功能 3.知识点总结 4.coding代码 1.Window open() 方法 效果图   2.adm ...

  5. Ubuntu Linux Recovery Mode

    在安全模式/修復模式有以下的選項︰resume Resume normal boot繼續正常啟動作業,供不小心誤入此選單的使用者開機使用.(继续以正常模式启动) clean Try to make f ...

  6. Mysql连接数、线程数、数据包

    https://blog.csdn.net/qq_26545305/article/details/79675507

  7. java kill thread command line

    multithreading - How do you kill a Thread in Java? - Stack Overflowhttps://stackoverflow.com/questio ...

  8. 什么是arp协议?

    转自:https://blog.csdn.net/tigerjibo/article/details/7351992 ARP (Address Resolution Protocol) 是个地址解析协 ...

  9. C#设计模式之4:装饰者模式

    装饰者模式 背景是有一家星巴兹咖啡店,由于客源充足,所以决定重新设计他们的收费系统,以前的收费系统中只定义了一个表示饮料的Beverage的基类,它里面定义了一个Cost的方法用来计算饮料的花费,但是 ...

  10. gulp项目和webpack项目在浏览器中查看的方式

    在存在.git的目录下,按住shift+左键,打开命令行或者使用git Bash Gulp: 输入gulp dev 本地起一个服务器,在项目中找到gulp.js,然后找本地服务器,找到host和por ...