LOJ2316. 「NOIP2017」逛公园【DP】【最短路】【思维】
思路
因为我想到的根本不是网上的普遍做法
所以常数出奇的大,而且做法极其暴力
可以形容是带优化的大模拟
进入正题:
首先一个很显然的思路是如果在合法的路径网络里面存在零环是有无数组解的
然后这个直接对所有边权是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】【最短路】【思维】的更多相关文章
- 【LOJ2316】「NOIP2017」逛公园
[题目链接] [点击打开链接] [题目概括] 对给定\(K\),起点\(1\)到终点\(n\)中对长度为\([L,L+K]\)的路径计数. \(L\)为\(1\)到\(n\)的最短路长度. [思路要点 ...
- 「NOIP2017」逛公园
传送门 Luogu 解题思路 考虑 \(\text{DP}\). 设 \(f[u][k]\) 表示从 \(u\) 到 \(n\) 走过不超过 \(Mindis(u, n) + k\) 距离的方案数. ...
- 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)
题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...
- P3953 逛公园(dp,最短路)
P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- 【题解】NOIP2017逛公园(DP)
[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...
- [luogu P3953] [noip2017 d1t3] 逛公园
[luogu P3953] [noip2017 d1t3] 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N ...
- 「NOIP2017」宝藏
「NOIP2017」宝藏 题解 博客阅读效果更佳 又到了一年一度NOIPCSP-S 赛前复习做真题的时间 于是就遇上了这道题 首先观察数据范围 \(1 \le n \le 12\) ,那么极大可能性是 ...
- 「WC2013」糖果公园
「WC2013」糖果公园 传送门 树上带修莫队板子题. 看懂题意后就是板子题了. 参考代码: #include <algorithm> #include <cstdio> #i ...
- 逛公园「NOIP2017」最短路+DP
大家好我叫蒟蒻,这是我的第一篇信竞题解blog [题目描述] 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园 ...
随机推荐
- html5语法改变
<!doctype html> 简化了 <meta http-equiv="Content-type" content="text/html;chars ...
- echarts 饼状图 改变折线长度
$(function (){ //ups部分 var myChart = echarts.init(document.getElementById('result')) var option = { ...
- Qt多线程同步总结
1.QMutex QMutex mutex; void func() { mutex.lock(); ........ mutex.unlock(); } 2.QMutex联手QMutex ...
- C++ string和C风格字符串
https://msdn.microsoft.com/en-us/library/syxtdd4f.aspx#basic_string__replace If you need to convert ...
- 20145204《Java程序设计》第3周学习总结
20145204<Java程序设计>第3周学习总结 教材学习内容总结 对象和类. Java有基本类型和类类型这两个类型系统.本章主要介绍类类型.定义类时用关键词class,利用类建立对象实 ...
- nvm命令行操作命令
1,nvm nvm list 是查找本电脑上所有的node版本 - nvm list 查看已经安装的版本 - nvm list installed 查看已经安装的版本 - nvm list avail ...
- Maven mybatis-generator自动生成代码
mybatis-generator可以自动生成代码,不管你是否喜欢它生成的代码的风格,它确实有助于我们更快速便捷的生成代码. Maven pom文件配置: <build> <plug ...
- python 获取5天前的日期
from datetime import date, timedelta dt = date.today() - timedelta() print('Current Date :',date.tod ...
- RabbitMQ入门_01_简介与安装
A. 资源与参考文档 官网:https://www.rabbitmq.com/ B. 学习目的 部门目前使用其他部门维护的 WebLogic 的 JMS 消息服务,缺乏足够的技术支持与运维支持.随着基 ...
- Mysql中FIND_IN_SET和REPLACE函数简介
一 FIND_IN_SET() SELECT * from u_user where FIND_IN_SET('32',tags) 上面的sql是精确查找,查找表中tags中含有32的记录(注意这里 ...