【比赛】NOIP2017 逛公园


考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了。
后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜。
看这道题,我们首先来想有哪些情况是-1:只要有零环在满足题目要求的路径上,那么这条路径就可以不停地走,于是就-1了。
如何判有没有零环呢?
机械化地两遍不同方向的SPFA,就知道某个点在不在最短路上,以此建一个最短路图,在最短路图上找零环。于是就拓扑啦。稍加判断就解决了整个题目最关键的-1。
接下来就是DP了,设f[i][j]表示走到i点,走过路程已经超过i点到n点最短路径长度j的方案数。假设我们知道u点的f[u][k],接下来我们会走到v。那么如果走的这条边正好是最短路上的边,f[v][k]+=f[u][k];否则,我们根据f[u][k]知道现在已走路程为dis[u]+k,走完这条边后,就是dis[u]+k+w[i],这些路程会超过v到n的最短路长度dis[u]+k+w[i]-dis[v]这么长,所以,f[v][dis[u]+k+w[i]-dis[v]]+=[u][k]。
大体就是这样,剩下一些小细节就看代码吧。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=+,MAXM=+,MAXK=+,inf=0x3f3f3f3f;
int n,m,Mod,k,e,qe,beg[MAXN],qbeg[MAXN],dis1[MAXN],p[MAXN],dis2[MAXN],nex[MAXM],qnex[MAXM],w[MAXM],qw[MAXM],to[MAXM],qto[MAXM],Indegree[MAXN],f[MAXN][MAXK],cnt,topoorder[MAXN];
inline void read(int &x)
{
int data=,w=;
char ch=;
while(ch!='-'&&(ch<''||ch>''))ch=getchar();
if(ch=='-')w=-,ch=getchar();
while(ch>=''&&ch<='')data=(data<<)+(data<<)+(ch^''),ch=getchar();
x=data*w;
}
inline void chksum(int &a,int b)
{
a+=b;
if(a>Mod)a-=Mod;
}
inline void insert(int x,int y,int z)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
w[e]=z;
qto[++qe]=x;
qnex[qe]=qbeg[y];
qbeg[y]=qe;
qw[qe]=z;
}
inline void init()
{
e=;
memset(beg,,sizeof(beg));
qe=;
memset(qbeg,,sizeof(qbeg));
memset(f,,sizeof(f));
cnt=;
memset(Indegree,,sizeof(Indegree));
}
inline void SPFA()
{
queue<int> q;
for(register int i=;i<=n;++i)dis1[i]=inf,p[i]=;
q.push();
p[]=;
dis1[]=;
while(!q.empty())
{
int x=q.front();
q.pop();
p[x]=;
for(register int i=beg[x];i;i=nex[i])
if(dis1[to[i]]>dis1[x]+w[i])
{
dis1[to[i]]=dis1[x]+w[i];
if(!p[to[i]])
{
p[to[i]]=;
q.push(to[i]);
}
}
}
for(register int i=;i<=n;++i)dis2[i]=inf,p[i]=;
q.push(n);
p[n]=;
dis2[n]=;
while(!q.empty())
{
int x=q.front();
q.pop();
p[x]=;
for(register int i=qbeg[x];i;i=qnex[i])
if(dis2[qto[i]]>dis2[x]+qw[i])
{
dis2[qto[i]]=dis2[x]+qw[i];
if(!p[qto[i]])
{
p[qto[i]]=;
q.push(qto[i]);
}
}
}
}
inline void toposort()
{
queue<int> q;
for(register int x=;x<=n;++x)
for(register int i=beg[x];i;i=nex[i])
if(dis1[to[i]]==dis1[x]+w[i])Indegree[to[i]]++;
for(register int i=;i<=n;++i)
if(!Indegree[i])q.push(i),topoorder[++cnt]=i;
while(!q.empty())
{
int x=q.front();
q.pop();
for(register int i=beg[x];i;i=nex[i])
if(dis1[to[i]]==dis1[x]+w[i])
{
Indegree[to[i]]--;
if(!Indegree[to[i]])q.push(to[i]),topoorder[++cnt]=to[i];
}
}
}
inline void DP()
{
f[][]=;
for(register int j=;j<=k;++j)
{
for(register int p=;p<=cnt;++p)
{
int x=topoorder[p];
for(register int i=beg[x];i;i=nex[i])
if(dis1[to[i]]==dis1[x]+w[i])chksum(f[to[i]][j],f[x][j]);
}
for(register int x=;x<=n;++x)
for(register int i=beg[x];i;i=nex[i])
if(dis1[to[i]]!=dis1[x]+w[i]&&j+dis1[x]+w[i]-dis1[to[i]]<=k)chksum(f[to[i]][j+dis1[x]+w[i]-dis1[to[i]]],f[x][j]);
}
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
int T;
read(T);
while(T--)
{
init();
read(n);read(m);read(k);read(Mod);
int mark=;
for(register int i=;i<=m;++i)
{
int u,v,w;
read(u);read(v);read(w);
insert(u,v,w);
}
SPFA();
toposort();
for(register int i=;i<=n;++i)
if(Indegree[i]&&dis1[i]+dis2[i]<=dis1[n]+k)
{
printf("-1\n");
mark=;
break;
}
if(mark)continue;
DP();
int ans=;
for(register int i=;i<=k;++i)chksum(ans,f[n][i]);
printf("%d\n",ans);
}
return ;
}
NOIP2017 逛公园
【比赛】NOIP2017 逛公园的更多相关文章
- [NOIP2017] 逛公园
[NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...
- 【题解】NOIP2017逛公园(DP)
[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...
- NOIP2017逛公园(dp+最短路)
策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会 ...
- NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】
题目描述 策策同学特别喜欢逛公园.公园可以看成一张NNN个点MMM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花 ...
- [NOIP2017]逛公园 题解
我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ...
- [NOIP2017] 逛公园 解题报告(DP)
我很不想说 在我的AC代码上我打了表,但实在没有办法了.莫名的8,9个点RE.然而即便是打表...也花了我很久. 这大概是NOIP2017最难的题了,为了让不懂的人更容易理解,这篇题解会比较详细 我的 ...
- [NOIP2017] 逛公园 【最短路】【强连通分量】
题目分析: 首先考虑无数条的情况.出现这种情况一定是一条合法路径经过了$ 0 $环中的点.那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离.加起来若离最短路径不超过$ k $则输出$ ...
- luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)
先跑一边dijkstra算出从1到i的最短距离dis[i] 然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数 答案就是$\sum\limits_{i=0}^{k} ...
- noip2017逛公园
题解: 之前知道正解并没有写过.. #include <bits/stdc++.h> using namespace std; #define rint register int #def ...
随机推荐
- Python之pexpect详解
一.引子 Pexpect程序主要用于人机对话的模拟,就是那种系统提问,人来回答yes/no,或者账号登陆输入用户名和密码等等的情况.因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现.最初的第 ...
- Unity学习笔记(4): 碰撞相关API
Unity3D中的碰撞: 在unity中,有普通碰撞体Collider和触发器(Trigger)两种碰撞体,两个普通碰撞体会发生碰撞并产生力学现象,触发器则像是个无法触碰而又真实存在的东西,也会触发碰 ...
- Python3列表中获取相同元素出现位置的下标
前言 list: Python3的列表类型, 和其他语言中的数组类似 定义格式: l = ["a", "b", "c", "a&q ...
- LinuxMint 18.3禁用ipv6
编辑/etc/sysctl.conf文件,添加如下内容 net.ipv6.conf.all.disable_all = 1 保存后执行 sudo sysctl -p 即可生效
- NO---20 文件上传
文件上传是我们会经常用到的一个业务,其实在h5中新增了FormData的对象,用它来提交表单,并且可以提交二进制文件,所以今天就写写文件上传,希望可以对大家有帮助 FormData 上传文件实例 首先 ...
- SQLAlchemy并发写入引发的思考
背景 近期公司项目中加了一个积分机制,用户登录签到会获取登录积分,但会出现一种现象就是用户登录时会增加双倍积分,然后生成两个积分记录.此为问题 问题分析 项目采用微服务架构,下图为积分机制流程 ...
- SQLMAP学习笔记2 Mysql数据库注入
SQLMAP学习笔记2 Mysql数据库注入 注入流程 (如果网站需要登录,就要用到cookie信息,通过F12开发者工具获取cookie信息) sqlmap -u "URL" - ...
- Java那些事-泛型通配符
Java的类型通配符,可以出现在类.方法上面.最常用的方式就是集合类,例如List,Set等类上面. 通配符类型 有泛型参数 List 有无类型标识 List< ? > 有通用的标识 Li ...
- CS224n-作业1
0 前言 作业1对应的试题 作业1对应的启动代码 作业1主页 1 Softmax(10分) (a)(5分) 对于向量$x+c$的任一维度$i$,有: \begin{align*}\mbox{softm ...
- spring-boot rabbitMq 完整项目搭建,包括创建、发送、监听
写在开始 rabbitMq 代码按照三部分介绍 第一部分 交换机和队列的创建 第二部分 消息发送 第三部分 消息监听 第一部分 1 建立queue 2 建立exchange 3 exchange绑定q ...