考试的时候灵光一闪,瞬间推出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 逛公园的更多相关文章

  1. [NOIP2017] 逛公园

    [NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...

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

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

  3. NOIP2017逛公园(dp+最短路)

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

  4. NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】

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

  5. [NOIP2017]逛公园 题解

    我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ...

  6. [NOIP2017] 逛公园 解题报告(DP)

    我很不想说 在我的AC代码上我打了表,但实在没有办法了.莫名的8,9个点RE.然而即便是打表...也花了我很久. 这大概是NOIP2017最难的题了,为了让不懂的人更容易理解,这篇题解会比较详细 我的 ...

  7. [NOIP2017] 逛公园 【最短路】【强连通分量】

    题目分析: 首先考虑无数条的情况.出现这种情况一定是一条合法路径经过了$ 0 $环中的点.那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离.加起来若离最短路径不超过$ k $则输出$ ...

  8. luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)

    先跑一边dijkstra算出从1到i的最短距离dis[i] 然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数 答案就是$\sum\limits_{i=0}^{k} ...

  9. noip2017逛公园

    题解: 之前知道正解并没有写过.. #include <bits/stdc++.h> using namespace std; #define rint register int #def ...

随机推荐

  1. 控制台报错: SCRIPT1006: Expected ')'

    今天做网站的时候,jsp页面取一个值死活取不出来. <script> if(${not empty requestScope.article.articleId}){ alert(${re ...

  2. Python科学测量与计算库Pymeasure: 控制你的仪器进行自动测试和科学计算

    Python这种脚本语言因其语法简单,工具包丰富成熟,使用起来非常方便.在很多领域被广泛使用,今天介绍的是python在仪器控制应用领域,python在仪器控制领域相关的书籍可以参考<真实世界的 ...

  3. [文章存档]Kudu 的 Debug Console 窗口如何查看更多文件

    链接:https://docs.azure.cn/zh-cn/articles/azure-operations-guide/app-service-web/aog-app-service-web-h ...

  4. RHEL7 利用单个物理网卡实现VLAN

    使用nmcli创建网桥配置 #nmcli connection add type bridge con-name br0 stp no 使用nmcli创建VLAN设备配置 #nmcli connect ...

  5. 【Docker】第三篇 Docker容器管理

    一.Docker容器概述: 简单理解容器是镜像的一个实例. 镜像是静态的只读文件,而容器的运行需要可写文件层. 二.创建容器 [root@web130 ~]# docker create -it ub ...

  6. 用线性分类器实现预测鸢尾花的种类(python)

    这是个人学习时跑的代码,结果就不贴了,有需要的可以自己运行,仅供参考,有不知道的可以私下交流,有问题也可以联系我.当然了我也只能提供一点建议,毕竟我也只是初学者 第一个页面 # -*- coding: ...

  7. ipcs命令详解

    基础命令学习目录首页 多进程间通信常用的技术手段包括共享内存.消息队列.信号量等等,Linux系统下自带的ipcs命令是一个极好的工具,可以帮助我们查看当前系统下以上三项的使用情况,从而利于定位多进程 ...

  8. LeetCode 566. Reshape the Matrix (C++)

    题目: In MATLAB, there is a very useful function called 'reshape', which can reshape a matrix into a n ...

  9. Teamwork#3,Week5,Scrum Meeting 11.20

    到目前为止,第一轮迭代已经基本完成.由于时间问题,多店比较的高级功能要放到第二轮迭代实现. 大部分任务已经完成,在alpha版本发布之前我们剩余需要解决的问题有两个: 服务器.校园网服务器不能满足我们 ...

  10. TeamWork#3,Week5,Introduction to the "take-away" Sale Selection Project

    一.NABCD 1.N(Need 需求) 当今社会生活节奏快,很多大学生.上班族叫外卖比较普遍,外卖生意异常火爆.最近美团.饿了么等外卖服务竞争激烈,产生了大量外卖优惠信息.而网络上外卖信息比较混乱, ...