[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决定也为奶牛们建 一个水上乐园. ...
随机推荐
- 说说流控制(RTS/CTS/DTR/DSR 你都明白了吗?)【转】
转自:http://bbs.ednchina.com/BLOG_ARTICLE_129041.HTM 以前写的博文,转过来 ============== 先引用一篇网文,作者不详,因几个地方都说自己是 ...
- oracle查看表名称和表字段注释
--查询该表字段的注释select * from user_col_comments where Table_Name like '%SMS%' --查询类似表select * from user_t ...
- zabbix系列(八)zabbix添加对web页面url的状态监控
通过zabbi做web监控不仅仅可以监控到站点的响应时间,还可以根据站点返回的状态码,或者响应时间做报警 1.对需要监控的主机添加web监控 在configuration—hosts 中打开主机列 ...
- 【SVN技巧】如何协同开发LabVIEW代码 1
前言 在我们工作中,必然会遇到代码的多个版本问题,也必然会遇到版本控制问题.如果所在的公司具有良好的项目管理体系或者软件管理体系,那么其版本控制应该有严格的使用规范,如果没有则作为一个上进好青年也应当 ...
- CentOs 6.6里kdump启动失败的原因
在VMware中新安装了CentOs 6.6,重启系统发现kdump服务启动失败 先来说一下,什么是kdump kdump 是一种先进的基于 kexec 的内核崩溃转储机制.当系统崩溃时,kdump ...
- 支付宝&微信统一支付
1.实体对应关系: Application — 支付记录实体 -- 支付记录详情 2.流程 1.生成订单选择支付类型 2.支付宝:PC端.手机端.扫码:微信:微信公众号支付.扫码支付.H5支付. ...
- androidpn 推送系统
(文中部分内容来自网络,如无意中侵犯了版权,请告之!) XMPP协议: XMPP : The Extensible Messaging andPresence Protocol. 中文全称:可扩展通讯 ...
- mysql5.7安装教程图解
启动安装包: 左边是你电脑上可以连接到mysql的软件,比如Visual Studio,Eclipse,PyCharm等,中间是需求的版本或者额外组件,右边是状态. 选择一个选项,然后点击下面的che ...
- js判断用户的浏览器
1,判断pc和移动端 function browserRedirect() { var sUserAgent = navigator.userAgent.toLowerCase(); var bIsI ...
- PHP 将数组的值赋值给一组变量
经常需要将一个字符串分割成一组值,然后赋值给不同的变量. 逐行赋值非常繁琐,于是查了一下 PHP 中是否有类似 python 中 a, b = (a, b) 的操作. 果然有 $info = arra ...