[NOIP2017]逛公园 最短路+拓扑排序+dp
题目描述
给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数。求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 $-1$ 。
输入
第一行包含一个整数 $T$ , 代表数据组数。
接下来 $T$ 组数据,对于每组数据: 第一行包含四个整数 $N,M,K,P$ ,每两个整数之间用一个空格隔开。
接下来 $M$ 行,每行三个整数 $a_i,b_i,c_i$ ,代表编号为 $a_i,b_i$ 的点之间有一条权值为 $c_i$ 的有向边,每两个整数之间用一个空格隔开。
输出
输出文件包含 $T$ 行,每行一个整数表示答案。
样例输入
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
样例输出
3
-1
题解
最短路+拓扑排序+dp
首先使用堆优化Dijkstra或Spfa(不知道本题是否会卡)求出1到所有点的最短路。
由于对于所有边 $(x,y,z)$ 满足 $dis[x]+z\ge dis[y]$ ,因此超过最短路的部分不会减少。
那么我们设 $f[i][j]$ 表示到达点 $i$ 时经过的路径总长度为 $dis[i]+j\ (j \le k)$ 的方案数。那么这相当于一个新的分层图,只会在同层或向上层转移,不会像下层转移。
这就转化为图上求路径条数。首先初始化 $f[1][0]=0 $ ,跑拓扑排序的同时进行转移。
如果一个点被排到了,那么 $f$ 值即为路径条数。
如果一个点没有被排到,则说明有环连接到它,即路径条数为 $\infty$。
因此把所有 $f[n][0...k]$ 统计一下即可。
时间复杂度 $O(T(m\log n+mk))$
考场上一眼看出题解,然而卡了两个小时的常数才勉强卡进去...
考场原代码(去掉了文件操作):
#include <queue>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define M 200010
#define R register
#define pos(x , y) (x + (y) * n)
using namespace std;
typedef pair<int , int> pr;
priority_queue<pr> q;
int head[N] , to[M] , len[M] , next[M] , cnt , dis[N] , vis[N];
int ll[N * 51] , rr[N * 51] , tt[M * 51] , que[N * 51] , ind[N * 51] , f[N * 51];
inline void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
inline char nc()
{
static char buf[100000] , *p1 , *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
int ret = 0; char ch = nc();
while(!isdigit(ch)) ch = nc();
while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
return ret;
}
int main()
{
int T = read();
while(T -- )
{
memset(head , 0 , sizeof(head));
memset(vis , 0 , sizeof(vis));
memset(ind , 0 , sizeof(ind));
memset(f , 0 , sizeof(f));
cnt = 0;
int n = read() , m = read() , k = read() , z , ans = 0 , flag = 1;
R int p = read() , i , j , x , y , l = 1 , r = 0;
for(i = 1 ; i <= m ; ++i) x = read() , y = read() , z = read() , add(x , y , z);
memset(dis , 0x3f , sizeof(dis));
dis[1] = 0 , q.push(pr(0 , 1));
while(!q.empty())
{
x = q.top().second , q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(dis[to[i]] > dis[x] + len[i])
dis[to[i]] = dis[x] + len[i] , q.push(pr(-dis[to[i]] , to[i]));
}
cnt = 0;
for(x = 1 ; x <= n ; ++x)
{
for(j = 0 ; j <= k ; ++j)
{
ll[pos(x , j)] = cnt + 1;
for(i = head[x] ; i ; i = next[i])
if(j + dis[x] + len[i] - dis[to[i]] <= k)
++ind[tt[++cnt] = pos(to[i] , j + dis[x] + len[i] - dis[to[i]])];
rr[pos(x , j)] = cnt;
}
}
f[1] = 1;
for(x = 1 ; x <= pos(n , k) ; ++x)
if(!ind[x])
que[++r] = x;
while(l <= r)
{
x = que[l ++ ];
for(i = ll[x] ; i <= rr[x] ; ++i)
{
y = tt[i];
f[y] += f[x] , ind[y] -- ;
if(f[y] >= p) f[y] -= p;
if(!ind[y]) que[++r] = y;
}
}
for(i = 0 ; i <= k ; ++i)
{
if(ind[pos(n , i)]) flag = 0;
ans = (ans + f[pos(n , i)]) % p;
}
if(flag) printf("%d\n" , ans);
else puts("-1");
}
return 0;
}
[NOIP2017]逛公园 最短路+拓扑排序+dp的更多相关文章
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...
- 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP
[BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...
- NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)
神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性, ...
- [NOIP2017]逛公园 最短路图 拓扑序DP
---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ...
- [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)
题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...
- 【题解】NOIP2017逛公园(DP)
[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...
- 【比赛】NOIP2017 逛公园
考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在 ...
- [NOIP2017] 逛公园
[NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...
- BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP
BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP Description 受到秘鲁的马丘比丘的新式水上乐园的启发,Farmer John决定也为奶牛们建 一个水上乐园. ...
随机推荐
- Dubbo本地存根
在远程调用服务提供者的实现之前,如果需要做一些参数验证.缓存.判断.小功能等等,满足要求再调用服务提供者的远程服务,则我们可以通过编写一个本地存根来实现这种功能. (1).在公共项目中或服务消费者项目 ...
- 蓝牙Bluetooth技术手册规范下载【转】
蓝牙Bluetooth技术手册规范下载 http://www.crifan.com/summary_bluetooth_specification_download/ [背景] 之前就已经整理和转帖了 ...
- nodejs的process模块如何获取其他进程的pid
var cmd=process.platform=='win32'?'tasklist':'ps aux'; var exec = require('child_process').exec; var ...
- Python3学习笔记23-StringIO和BytesIO
StringIO 很多时候数据读取不一定是文件,也可以在内存中 StringIO顾名思义就是在内存中读写str 要把str写入StringIO,我们需要先创建一个StringIO,然后像文件一样写入即 ...
- spring上传文件
在使用spring上传文件的时候,使用的文件接收参数类型为 org.springframework.web.multipart.MultipartFile 如果该参数没有指定@RequestParam ...
- Java编码与乱码问题
一.为什么要编码? 由于人类的语言太多,因而表示这些语言的符号太多,无法用计算机的一个基本的存储单元----byte来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解. byte一个字节即8 ...
- 浏览器的userAgent归纳
IE IE6 User-Agent:Mozilla/4.0 (Windows; MSIE 6.0; Windows NT 5.2) IE7 User-Agent:Mozilla/4.0 (compat ...
- django----Form扩展
用第二种方式需要加上下面的这个: 三.判断用户民是不存在,存在就不添加了 from django.core.exceptions import ValidationError initial 修改时 ...
- poj3585 树形dp 二次扫描,换根法模板题
#include<iostream> #include<cstring> #include<cstdio> #include<vector> using ...
- 性能测试二十一:环境部署之mysql
在正常工作中,mysql应该部署到 一台独立的服务器上,不与tomcat共用服务器,由于成本原因,现部署到一起 为避免出错引起麻烦,先备份: 一:环境清理:先卸载系统自带的mysql 停止mysql: ...