题目分析:

首先考虑无数条的情况。出现这种情况一定是一条合法路径经过了$ 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. redis-trib.rb命令详解

    redis-trib.rb是官方提供的Redis Cluster的管理工具,无需额外下载,默认位于源码包的src目录下,但因该工具是用ruby开发的,所以需要准备相关的依赖环境. 准备redis-tr ...

  2. bootstrapValidator表单验证插件

    bootstrapValidator——一个很好用的表单验证插件,再也不用手写验证规则啦! bootstrapValidator官方文档:http://bootstrapvalidator.votin ...

  3. mariadb(第一章)

      数据库介绍 1.什么是数据库? 简单的说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织,存储的,我们可以通过数据库提供的多种方法来 ...

  4. H5 文字属性的缩写

    05-文字属性的缩写 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  5. 使用 Markdown编辑

    作用: 学习笔记,整理日志, 发布日记,杂文,所见所想 撰写发布技术文稿(代码支持) 撰写发布学术论文(LaTeX 公式支持) sublime text3插件 输入 Shift + Ctrl + P, ...

  6. MySQL 深入浅出数据库索引原理(转)

    本文转自:https://www.cnblogs.com/aspwebchh/p/6652855.html 前段时间,公司一个新上线的网站出现页面响应速度缓慢的问题, 一位负责这个项目的但并不是搞技术 ...

  7. 17-vue-cli脚手架安装和webpack-simple模板项目生成

    ue-cli 是一个官方发布 vue.js 项目脚手架,使用 vue-cli 可以快速创建 vue 项目. GitHub地址是:https://github.com/vuejs/vue-cli 一.安 ...

  8. centos安装bundle文件

    centos安装VMware-Workstation-Full-*.bundle那点事 | 鳗鱼是条狗https://kinggoo.com/centos-vmware.htm Linux 下 VMW ...

  9. mysql 无法退出sql命令行编辑

    mysql 无法退出sql命令行编辑 | ANBOBhttp://www.anbob.com/archives/579.html mysql 无法退出sql命令行编辑 - 码农甲乙丙 - CSDN博客 ...

  10. Proper usage of Java -D command-line parameters

    https://stackoverflow.com/questions/5045608/proper-usage-of-java-d-command-line-parameters https://c ...