LINK

思路

因为我想到的根本不是网上的普遍做法

所以常数出奇的大,而且做法极其暴力

可以形容是带优化的大模拟

进入正题:

首先一个很显然的思路是如果在合法的路径网络里面存在零环是有无数组解的

然后这个直接对所有边权是0的边进行一次toposort看看有没有点没有被访问到

然后剩下的dp怎么设计?

\(dp_{i,j}\)表示走到了第i个点,如果当前点到n走最短路最后路径比最短路径多出来了j

然后转移的时候发现是需要搞定顺序的问题?咋办?

发现一条边新的贡献是\(dis2_{v}+E[i].w-dis2_u\),其中dis2是反图跑出来的最短路

然后就可以把每条边的权值换一下

发现这个时候我们要先枚举j进行转移

这样就把状态转移分成了若干个层次

然后发现新的边权如果是0的话会在同一层之间转移

并且可以保证新的边权是没有0环的

那就再做一遍toposort就好了

随便跑一跑多好的

然后同一层你就先跑所有新的权值是0的边,同层转移完了之后你再跑权值不是0的边转移到下一层就可以了


附带Debug全套餐。。。良心对拍程序(懒得删了)


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
//#define Debug
typedef pair<int, int> pi;
const int N = 2e5 + 10;
const int M = 55;
struct Edge {
int u, v, w, nxt;
bool dir, eras;
} E[N << 1];
int head[N], tot = 0, vis[N];
int dis1[N], dis2[N], deg[N], topoid[N];
int n, m, k, p, minidis, dp[N][M];
void init() {
tot = 0;
fu(i, 1, n) head[i] = deg[i] = 0;
fu(i, 1, n)
fu(j, 0, k) dp[i][j] = 0;
}
void addedge(int u, int v, int w) {
#ifdef Debug
printf("EDGE:[%d, %d]: %d\n", u, v, w);
#endif
E[++tot] = (Edge) {u, v, w, head[u], 0, 0}, head[u] = tot;
E[++tot] = (Edge) {v, u, w, head[v], 1, 0}, head[v] = tot;
}
void add(int &a, int b) {
if ((a += b) >= p) a -= p;
}
void Dijkstra1() {
static priority_queue<pi, vector<pi>, greater<pi> > q;
fu(i, 1, n) dis1[i] = INF_of_int, vis[i] = 0;
dis1[1] = 0;
q.push(pi(dis1[1], 1));
while (q.size()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (!E[i].dir && dis1[v] > dis1[u] + E[i].w) {
dis1[v] = dis1[u] + E[i].w;
q.push(pi(dis1[v], v));
}
}
}
}
void Dijkstra2() {
static priority_queue<pi, vector<pi>, greater<pi> > q;
fu(i, 1, n) dis2[i] = INF_of_int, vis[i] = 0;
dis2[n] = 0;
q.push(pi(dis2[n], n));
while (q.size()) {
int u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (E[i].dir && dis2[v] > dis2[u] + E[i].w) {
dis2[v] = dis2[u] + E[i].w;
q.push(pi(dis2[v], v));
}
}
}
}
bool toposort() {
int ind = 0;
fu(i, 1, n) vis[i] = 0;
fu(i, 1, tot) {
if (E[i].eras || E[i].w) continue;
deg[E[i].v]++;
}
static queue<int> topo;
fu(i, 1, n) if (!deg[i]) topo.push(i);
while (topo.size()) {
int u = topo.front(); topo.pop();
#ifdef Debug
printf("Topotost :: Reach: %d\n", u);
#endif
topoid[++ind] = u, vis[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (E[i].w || E[i].eras) continue;
if (--deg[v] == 0) topo.push(v);
}
}
fu(i, 1, n) if (deg[i]) return 1;
fu(i, 1, n) if (!vis[i]) topoid[++ind] = i;
return 0;
}
void DP() {
dp[1][0] = 1;
fu(j, 0, k) {
#ifdef Debug
printf("In the case :: %d\n", j);
#endif
fu(id, 1, n) if (dp[topoid[id]][j]) {
int u = topoid[id];
for (int i = head[u]; i; i = E[i].nxt) {
if (E[i].eras || E[i].w) continue;
int v = E[i].v;
add(dp[v][j], dp[u][j]);
#ifdef Debug
printf("Trans between:[%d, %d] :: old value : %d new value : %d\n", u, v, j, E[i].w);
#endif
}
}
fu(id, 1, n) if (dp[topoid[id]][j]) {
int u = topoid[id];
for (int i = head[u]; i; i = E[i].nxt) {
if (E[i].eras || !E[i].w) continue;
int v = E[i].v;
if (j + E[i].w > k) continue;
add(dp[v][j + E[i].w], dp[u][j]);
#ifdef Debug
printf("Trans between:[%d, %d] :: old value : %d new value : %d\n", u, v, j, E[i].w);
#endif
}
}
}
}
void solve() {
Read(n), Read(m), Read(k), Read(p);
init();
fu(i, 1, m) {
int u, v, w;
Read(u), Read(v), Read(w);
addedge(u, v, w);
}
Dijkstra1();
Dijkstra2();
#ifdef Debug
fu(i, 1, n) cout<<dis1[i]<<" "<<dis2[i]<<endl;
#endif
minidis = dis1[n];
if (dis1[n] >= INF_of_int) {
printf("0\n");
return;
}
fu(i, 1, tot) {
if (!E[i].dir) {
if (dis1[E[i].u] + E[i].w + dis2[E[i].v] > minidis + k) E[i].eras = 1;
} else E[i].eras = 1;
}
if (toposort()) {
printf("-1\n");
return;
}
fu(i, 1, tot) {
if (E[i].eras) continue;
E[i].w = dis2[E[i].v] - dis2[E[i].u] + E[i].w;
}
toposort();
#ifdef Debug
fu(i, 1, n) printf("%d ", topoid[i]);
putchar('\n');
#endif
DP();
int ans = 0;
fu(i, 0, k) add(ans, dp[n][i]);
Write(ans), putchar('\n');
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
int T; Read(T);
while (T--) solve();
return 0;
}

LOJ2316. 「NOIP2017」逛公园【DP】【最短路】【思维】的更多相关文章

  1. 【LOJ2316】「NOIP2017」逛公园

    [题目链接] [点击打开链接] [题目概括] 对给定\(K\),起点\(1\)到终点\(n\)中对长度为\([L,L+K]\)的路径计数. \(L\)为\(1\)到\(n\)的最短路长度. [思路要点 ...

  2. 「NOIP2017」逛公园

    传送门 Luogu 解题思路 考虑 \(\text{DP}\). 设 \(f[u][k]\) 表示从 \(u\) 到 \(n\) 走过不超过 \(Mindis(u, n) + k\) 距离的方案数. ...

  3. 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)

    题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...

  4. P3953 逛公园(dp,最短路)

    P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...

  5. 【题解】NOIP2017逛公园(DP)

    [题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n​节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...

  6. [luogu P3953] [noip2017 d1t3] 逛公园

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

  7. 「NOIP2017」宝藏

    「NOIP2017」宝藏 题解 博客阅读效果更佳 又到了一年一度NOIPCSP-S 赛前复习做真题的时间 于是就遇上了这道题 首先观察数据范围 \(1 \le n \le 12\) ,那么极大可能性是 ...

  8. 「WC2013」糖果公园

    「WC2013」糖果公园 传送门 树上带修莫队板子题. 看懂题意后就是板子题了. 参考代码: #include <algorithm> #include <cstdio> #i ...

  9. 逛公园「NOIP2017」最短路+DP

    大家好我叫蒟蒻,这是我的第一篇信竞题解blog [题目描述] 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园 ...

随机推荐

  1. SQL语句中case函数

    case函数,严格的意义上来讲case函数已经试流程控制语句了,不是简单意义上的函数,不过为了方便,很多人将case函数称为流程控制函数. case函数的一般有两种用法:1.case expressi ...

  2. Linux 笔记 #01# 搭建 Python 环境 & vim 代码高亮

    日常收集 vim editor: How do I enable and disable vim syntax highlighting? 搭建 Python 环境 vim editor: How d ...

  3. poj2262 Goldbach's Conjecture

    poj2262 Goldbach's Conjecture 用欧拉筛把素数筛出来,再枚举一下. #include<iostream> #include<cstdio> #inc ...

  4. table中checkbox选择多行

    页面代码 <table id="addressTable" class="ui-jqgrid-htable ui-common-table table table- ...

  5. 20145120 《Java程序设计》实验五实验报告

    20145120 <Java程序设计>实验五实验报告 实验名称:Java网络编程 实验内容: 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验内容. ...

  6. Exception.StackTrace

    Exception中的StackTrace属性 执行堆栈跟踪在给定时刻正在执行的所有方法. 对方法调用的跟踪称为堆栈跟踪. 堆栈跟踪列表提供了一种循着调用堆叠跟踪到方法中异常发生处行号的手段.Stac ...

  7. 关于JS和JSON

    讲得不准确! 看网课,JS也算是面向对象的一门语言,不过其是解释性的脚本语言. JSON是把用JS的表示法将数据包装起来进行传递用的. JS语法是松散型的,没有int String这些像JAVA里的类 ...

  8. URL存在http host头攻击漏洞-修复方案

    URL存在http host头攻击漏洞-修复方案 spring boot使用注解的方式 -- 第一步:在自定义filter类上添加如下注释 package com.cmcc.hy.mobile.con ...

  9. 简单的spring mvc实例

    简单的springmvc实例 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&qu ...

  10. Python在七牛云平台的应用(一)

    七牛云:(引用百度的介绍)七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化PaaS服务.围绕富媒体场景,七牛先后推出了对象存储,融合CDN加速,数据通用处理,内容反垃圾服务,以及直 ...