NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)
神tm比赛时多清个零就有60了T T
首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP。设f[i][j]表示比最短路多走i的长度,到j的方案数。
我们发现如果在最短路上的和零边会有后向性,怎么办呢?拓扑排序。
把最短路上的点和零边的点拉出来跑拓扑排序,如果有零环的话必定度数不为0,而且要注意零环必须在<=最短路+k的路径上才输出-1,这个就用刚刚跑出来的1起点到n起点的最短路来判断就好了。
然后先按拓扑序DP出i相同的,然后再DP不在最短路上或者零边的。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
#define MOD(x) ((x)>=mod?(x)-mod:(x))
using namespace std;
const int maxn=;
struct tjm{int too, dis, pre;}e[][maxn];
struct poi{int x, dis;};
priority_queue<poi>q;
bool operator<(poi a, poi b){return a.dis>b.dis;}
int T, x, y, z, n, m, K, mod, top, tot[], ans;
int f[][maxn], dist[][maxn], last[][maxn], d[maxn], st[maxn];
void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-' && (f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
inline void add(int x, int y, int z, int ty){e[ty][++tot[ty]]=(tjm){y, z, last[ty][x]}; last[ty][x]=tot[ty];}
inline void dij(int x, int ty)
{
memset(dist[ty], , sizeof(dist[ty]));
dist[ty][x]=; q.push((poi){x, });
while(!q.empty())
{
poi now=q.top(); q.pop();
if(dist[ty][now.x]!=now.dis) continue;
for(int i=last[ty][now.x], too;i;i=e[ty][i].pre)
if(dist[ty][too=e[ty][i].too]>dist[ty][now.x]+e[ty][i].dis)
{
dist[ty][too]=dist[ty][now.x]+e[ty][i].dis;
q.push((poi){too, dist[ty][too]});
}
}
}
inline bool topo()
{
memset(d, , sizeof(d));
for(int i=;i<=n;i++)
for(int j=last[][i], too;j;j=e[][j].pre)
if(dist[][i]+e[][j].dis==dist[][too=e[][j].too]) d[too]++;
top=; for(int i=;i<=n;i++) if(!d[i]) st[++top]=i;
for(int i=;i<=top;i++)
for(int j=last[][st[i]], too;j;j=e[][j].pre)
if(dist[][st[i]]+e[][j].dis==dist[][too=e[][j].too])
{
d[too]--;
if(!d[too]) st[++top]=too;
}
for(int i=;i<=n;i++) if(d[i] && dist[][i]+dist[i][n]<=dist[][n]+K) return ;
return ;
}
int main()
{
read(T);
while(T--)
{
memset(last, , sizeof(last)); tot[]=tot[]=;
read(n); read(m); read(K); read(mod);
for(int i=;i<=m;i++) read(x), read(y), read(z), add(x, y, z, ), add(y, x, z, );
dij(, ); dij(n, );
if(!topo()) {puts("-1"); continue;}
memset(f, , sizeof(f)); f[][]=; ans=;
for(int i=;i<=K;i++)
{
for(int j=;j<=top;j++)
for(int k=last[][st[j]], too;k;k=e[][k].pre)
if(e[][k].dis+dist[][st[j]]==dist[][too=e[][k].too])
f[i][too]+=f[i][st[j]], f[i][too]=MOD(f[i][too]);
for(int j=;j<=n;j++)
for(int k=last[][j], too, tmp;k;k=e[][k].pre)
if((tmp=i+e[][k].dis+dist[][j]-dist[][too=e[][k].too])<=K && i!=tmp)
f[tmp][too]+=f[i][j], f[tmp][too]=MOD(f[tmp][too]);
ans+=f[i][n]; ans=MOD(ans);
}
printf("%d\n", ans);
}
}
NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)的更多相关文章
- [NOIP2017]逛公园 最短路+拓扑排序+dp
题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...
- NOIP2017 Day1 T3 逛公园
NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...
- 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP
[BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...
- 洛谷 3953 NOIP2017提高组Day1 T3 逛公园
[题解] 先建反向图,用dijkstra跑出每个点到n的最短距离dis[i] 设f[u][k]表示dis(u,n)<=mindis(u,n)+k的方案数.对于边e(u,v,w),走了这条边的话需 ...
- Luogu P3953 逛公园(最短路+记忆化搜索)
P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...
- BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP
BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP Description 受到秘鲁的马丘比丘的新式水上乐园的启发,Farmer John决定也为奶牛们建 一个水上乐园. ...
- POJ 3249 拓扑排序+DP
貌似是道水题.TLE了几次.把所有的输入输出改成scanf 和 printf ,有吧队列改成了数组模拟.然后就AC 了.2333333.... Description: MR.DOG 在找工作的过程中 ...
- 洛谷P3244 落忆枫音 [HNOI2015] 拓扑排序+dp
正解:拓扑排序+dp 解题报告: 传送门 我好暴躁昂,,,怎么感觉HNOI每年总有那么几道题题面巨长啊,,,语文不好真是太心痛辣QAQ 所以还是要简述一下题意,,,就是说,本来是有一个DAG,然后后来 ...
随机推荐
- Visual Studio设置字体及护眼背景色
打开vs 菜单栏选择: 工具 -> 选择 -> 环境 -> 字体和颜色,如图所示 字体可以如上选择,背景色选择项背景,点击自定义,如下设置即可.
- 关于C语言中内存的3个问题
1.程序为什么需要内存? 计算机程序 = 代码 + 结果,从宏观上理解,代码就是动作,而数据被动作加工,最终返回结果.程序是被放在内存中运行的,并且需要内存来存储一些临时变量,因此,对于程序来说,内存 ...
- vscode中安装使用markdown 插件
linux中好用的IDE vscode是微软推出的一款好用免费的IDE,可以快速部署开发环境,所说配置有些繁琐,但是瑕不掩瑜.它同时支持很多种拓展的编辑器,MarkDown只是其中的一种. 安装 ...
- Redis的数据类型以及每种数据类型的使用场景
人就是很奇怪的动物,很简单的问题往往大家都容易忽略,当我们在使用分布式缓存Redis的时候,一个最简单的问题Redis的数据类型以及每种数据类型的使用场景是什么? 是不是觉得这个问题很基础?我也这么觉 ...
- Numpy入门笔记第一天
# 导入包 import numpy as np # 创建一维数组 a = np.arange(5) print "一维numpy数组", a print "数组的类型& ...
- openresty 安装指南
对于一些常见的 Linux 发行版本,OpenResty 提供 官方预编译包.确保你首先用这种方式来安装. 如果您还没有下载 OpenResty 的源码包, 请到 Download 页下载. 首先,您 ...
- SVN服务器搭建及客户端配置
为什么要使用SVN? 在程序的编写过程中,每个程序员都会负责开发一个或多个模块,且开发中会生成很多不同的版本, 这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subvers ...
- 模拟登入教务处(header)
import HTMLParser import urlparse import urllib import urllib2 import cookielib import string import ...
- (Miller Rabin算法)判断一个数是否为素数
1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...
- lintcode-496-玩具工厂
496-玩具工厂 工厂模式是一种常见的设计模式.请实现一个玩具工厂 ToyFactory 用来产生不同的玩具类.可以假设只有猫和狗两种玩具. 您在真实的面试中是否遇到过这个题? Yes 样例 ToyF ...