神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)的更多相关文章

  1. [NOIP2017]逛公园 最短路+拓扑排序+dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...

  2. [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...

  3. NOIP2017 Day1 T3 逛公园

    NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...

  4. 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP

    [BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...

  5. 洛谷 3953 NOIP2017提高组Day1 T3 逛公园

    [题解] 先建反向图,用dijkstra跑出每个点到n的最短距离dis[i] 设f[u][k]表示dis(u,n)<=mindis(u,n)+k的方案数.对于边e(u,v,w),走了这条边的话需 ...

  6. Luogu P3953 逛公园(最短路+记忆化搜索)

    P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...

  7. BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP

    BZOJ_1916_[Usaco2010 Open]冲浪_分层图+拓扑排序+DP Description 受到秘鲁的马丘比丘的新式水上乐园的启发,Farmer John决定也为奶牛们建 一个水上乐园. ...

  8. POJ 3249 拓扑排序+DP

    貌似是道水题.TLE了几次.把所有的输入输出改成scanf 和 printf ,有吧队列改成了数组模拟.然后就AC 了.2333333.... Description: MR.DOG 在找工作的过程中 ...

  9. 洛谷P3244 落忆枫音 [HNOI2015] 拓扑排序+dp

    正解:拓扑排序+dp 解题报告: 传送门 我好暴躁昂,,,怎么感觉HNOI每年总有那么几道题题面巨长啊,,,语文不好真是太心痛辣QAQ 所以还是要简述一下题意,,,就是说,本来是有一个DAG,然后后来 ...

随机推荐

  1. Visual Studio设置字体及护眼背景色

    打开vs 菜单栏选择: 工具 -> 选择 -> 环境 -> 字体和颜色,如图所示 字体可以如上选择,背景色选择项背景,点击自定义,如下设置即可.

  2. 关于C语言中内存的3个问题

    1.程序为什么需要内存? 计算机程序 = 代码 + 结果,从宏观上理解,代码就是动作,而数据被动作加工,最终返回结果.程序是被放在内存中运行的,并且需要内存来存储一些临时变量,因此,对于程序来说,内存 ...

  3. vscode中安装使用markdown 插件

    linux中好用的IDE    vscode是微软推出的一款好用免费的IDE,可以快速部署开发环境,所说配置有些繁琐,但是瑕不掩瑜.它同时支持很多种拓展的编辑器,MarkDown只是其中的一种. 安装 ...

  4. Redis的数据类型以及每种数据类型的使用场景

    人就是很奇怪的动物,很简单的问题往往大家都容易忽略,当我们在使用分布式缓存Redis的时候,一个最简单的问题Redis的数据类型以及每种数据类型的使用场景是什么? 是不是觉得这个问题很基础?我也这么觉 ...

  5. Numpy入门笔记第一天

    # 导入包 import numpy as np # 创建一维数组 a = np.arange(5) print "一维numpy数组", a print "数组的类型& ...

  6. openresty 安装指南

    对于一些常见的 Linux 发行版本,OpenResty 提供 官方预编译包.确保你首先用这种方式来安装. 如果您还没有下载 OpenResty 的源码包, 请到 Download 页下载. 首先,您 ...

  7. SVN服务器搭建及客户端配置

    为什么要使用SVN? 在程序的编写过程中,每个程序员都会负责开发一个或多个模块,且开发中会生成很多不同的版本, 这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subvers ...

  8. 模拟登入教务处(header)

    import HTMLParser import urlparse import urllib import urllib2 import cookielib import string import ...

  9. (Miller Rabin算法)判断一个数是否为素数

    1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...

  10. lintcode-496-玩具工厂

    496-玩具工厂 工厂模式是一种常见的设计模式.请实现一个玩具工厂 ToyFactory 用来产生不同的玩具类.可以假设只有猫和狗两种玩具. 您在真实的面试中是否遇到过这个题? Yes 样例 ToyF ...