【NOIP 2017】逛公园
Description
策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从N号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出−1。
solution
正解:拓扑序DP
这题其实有两个拓扑序,一个是 \(dis[i]\) ,即1到 \(i\) 的最短路的长度,另外一个就是图本身的拓扑序了,我们单独拿出满足1到 任意一点\(i\) 最短路的边,然后做DP即可,状态设计为 \(f[i][j]\),表示到达点 \(i\),路径长度为 \(dis[i]+j\) 的方案数,然后枚举转移即可,判 \(-1\) 的方法很巧妙,因为边的长度为0,所以0环上的点的 \(dis\) 都满足拓扑序,也就是拓扑排序中会出现环,那么直接判掉即可,即如果存在某个0环上的一点 \(i\) 满足 \(dis[S][i]+dis[i][T]<=dis[S][T]+K\) 那么就有无穷多的方案数了
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=200005,inf=2e8;
int f[2][N],mod,n,m,K,head[N],nxt[N<<1],to[N<<1],dis[N<<1],num=0;
bool vis[N],imp[N];int Head[N];
void link(int x,int y,int z){
nxt[++num]=head[x];to[num]=y;dis[num]=z;head[x]=num;}
void Link(int x,int y,int z){
nxt[++num]=Head[x];to[num]=y;dis[num]=z;Head[x]=num;}
queue<int>q;
void priwork(bool t){
for(int i=1;i<=n;i++)vis[i]=0,f[t][i]=inf;
if(t==0)q.push(1),vis[1]=1,f[t][1]=0;
else q.push(n),vis[n]=1,f[t][n]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=(t?Head[x]:head[x]);i;i=nxt[i]){
RG int u=to[i];
if(f[t][x]+dis[i]<f[t][u]){
f[t][u]=f[t][x]+dis[i];
if(!vis[u])vis[u]=1,q.push(u);
}
}
vis[x]=0;
}
}
int dp[N][55],d[N],sum=0,Q[N];
void solve(){
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=nxt[j])
if(f[0][i]+dis[j]==f[0][to[j]])d[to[j]]++;
for(int i=1;i<=n;i++)if(!d[i])Q[++sum]=i;
RG int t=0;int x,u;
while(t!=sum){
x=Q[++t];
for(int i=head[x];i;i=nxt[i]){
u=to[i];
if(f[0][x]+dis[i]==f[0][u]){
d[u]--;
if(!d[u])Q[++sum]=u;
}
}
}
}
void Clear(){
memset(dp,0,sizeof(dp));
for(RG int i=0;i<N;i++)Q[i]=d[i]=head[i]=Head[i]=imp[i]=0;
sum=0;num=0;
}
inline void add(RG int &x,int y){x+=y;if(x>=mod)x-=mod;}
void work()
{
Clear();
int x,y,z;
scanf("%d%d%d%d",&n,&m,&K,&mod);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
link(x,y,z);Link(y,x,z);
}
priwork(0);priwork(1);solve();
for(int i=1;i<=n;i++)
if(d[i]>0 && f[0][i]+f[1][i]<=f[0][n]+K){
puts("-1");return ;
}
dp[1][0]=1;
for(int k=0;k<=K;k++){
for(int P=1;P<=sum;P++){
int i=Q[P];
if(!dp[i][k])continue;
for(RG int j=head[i];j;j=nxt[j]){
x=to[j];
if(f[0][i]+dis[j]==f[0][x])
add(dp[x][k],dp[i][k]);
}
}
for(RG int i=1;i<=n;i++){
if(!dp[i][k])continue;
for(RG int j=head[i];j;j=nxt[j]){
x=to[j];
if(f[0][i]+dis[j]!=f[0][x]
&& f[0][i]+k+dis[j]-f[0][x]<=K)
add(dp[x][f[0][i]+k+dis[j]-f[0][x]],dp[i][k]);
}
}
}
int ans=0;
for(int i=0;i<=K;i++)add(ans,dp[n][i]);
printf("%d\n",ans);
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
int T;cin>>T;
while(T--)work();
return 0;
}
【NOIP 2017】逛公园的更多相关文章
- [NOIp 2017]逛公园
Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- NOIP 2017 逛公园 记忆化搜索 最短路 好题
题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...
- NOIP 2017 逛公园 - 动态规划 - 最短路
题目传送门 传送门 题目大意 给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数. 跑一遍最短路. 一个点拆$K + 1$个点,变成一个DAG上路径计数问 ...
- 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP
题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...
- NOIP 2017 逛公园 题解
题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...
- [NOIP 2017 day1]逛公园
题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要 ...
- 逛公园[NOIP2017 D2 T3](dp+spfa)
题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\)个点\(M\) 条边构成的有向图,且没有自环和重边.其中 1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条 ...
- NOIP2017 Day1 T3 逛公园
NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...
随机推荐
- 解决python中flask_sqlalchemy包安装失败的问题
在进行flask_sqlalchemy包的下载安装时出现以下问题: 由图片可看出是编码转换出了问题,找到pip\compat_init_.py文件,打开它并查看第73行,将代码做如下更改并保存: 问题 ...
- 201621123062《Java程序设计》第一周学习总结
1.本周学习总结 关键词: 初步熟悉Java的基本组成.语言特点(简单性.结构中立性).运行环境.简单语法等. 关键概念之间的联系: 1.JVM是Java程序唯一认识的操作系统,其可执行文件为.cla ...
- 服务器数据恢复方法_存储raid硬盘离线数据恢复案例
[故障描述]某法院的一台HP-P4500的存储系统,底层是12块1TB的硬盘组的RAID.其中每6个1TB的盘一组,第一组的前面一部分组了一个RAID0+1,是存放HP-P4500嵌入式系统,接着组了 ...
- zookeeper 入门系列-理论基础 – zab 协议
上一章讨论了paxos算法,把paxos推到一个很高的位置.但是,paxos有没有什么问题呢?实际上,paxos还是有其自身的缺点的: 1. 活锁问题.在base-paxos算法中,不存在leader ...
- csrf学习笔记
CSRF全称Cross Site Request Forgery,即跨站点请求伪造.我们知道,攻击时常常伴随着各种各样的请求,而攻击的发生也是由各种请求造成的. CSRF攻击能够达到的目的是使受害者发 ...
- app测试中遇到问题总结
工作总结: 1 这两天由于工作,需要进行抓包,使用了Charles,fidder,发现一个坑点: charles没有抓到返回值的时候,默认是不在列表显示请求信息的,能不能设置,我就不知道了,但是可以在 ...
- New UWP Community Toolkit - RotatorTile
概述 UWP Community Toolkit 中有一个为图片或磁贴提供轮播效果的控件 - RotatorTile,本篇我们结合代码详细讲解 RotatorTile 的实现. RotatorTi ...
- 智能合约语言 Solidity 教程系列9 - 错误处理
这是Solidity教程系列文章第9篇介绍Solidity 错误处理. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文 ...
- python __str__ 和__repr__方法
看下面的例子就明白了 class Test(object): def __init__(self, value='hello, world!'): self.data = value >> ...
- gradle入门(1-8)gradle 的依赖查看、依赖排除和指定版本(需要验证!)
一.依赖查看 gradle dependencies 在gradle dependencies输出会有如下几种标记: 1.版本 : 唯一的依赖. 2.版本():还存在该库其他版本的依赖或者间接依赖,并 ...