考试的时候灵光一闪,瞬间推出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. Linux学习之常用系统工作命令(一)

     由于centos和RHEL互通,两个版本可以相互学习,所以截图有两个界面 Linux系统与win系列是两个几乎完全不同的操作系统,但是就应用范围来说,是win系统更胜一筹,然而,这反而也成为win系 ...

  2. flask的cookie和session的简单原理

    在Flask的框架中,自己已经封装了 cookie的respons,request 有存储就有读取及删除,那么就拿购物车来举例 在我们登陆的时候会有之前在购物车存放的物品.也就是说在一个地方为我们保存 ...

  3. webpack3升级为webpack4

    写在前面的话:为什么要升级,因为公司目前的项目使用webpack3,但是因为是多页应用,入口估计有一百多个,开发模式下慢得不像话,修改一个文件需要十几秒才编译好,之前的解决方案是减少入口,但是要调试其 ...

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

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

  5. PHPCMS 栏目添加字段和修改描述textarea变成fceditor编辑器

    一.添加字段方法: 1. 添加数据库字段:description1,添加位置:v9_catetory表 找到phpcms/moudles/admin/templates/category_add.tp ...

  6. 多表查询sql语句

    多表查询sql语句 1 --解锁SCOTT用户 2 alter user scott account unlock 3 --检索指定的列 4 select job,ename,empno from e ...

  7. 多tomcat 同一个浏览器 多个项目 会导致session覆盖

    1,多tomcat 同一个浏览器 同一个项目 会导致session覆盖 个人猜测:一个服务器中有多个Tomcat服务器多个项目,每个服务器占用不同的端口号,当在同一个浏览器里面同时打开2个系统时,一个 ...

  8. 为centos虚拟机配置固定ip

    在virtual上安装centos虚拟机以后,发现虚拟机没有ip,无法联网 将虚拟机的网络适配器改为桥接模式,桥接到物理机的无线网卡 为虚拟机配置固定IP(vi /etc/sysconfig/netw ...

  9. printf命令详解

    基础命令学习目录首页 本文是Linux Shell系列教程的第(八)篇,更多shell教程请看:Linux Shell系列教程 在上一篇:Linux Shell系列教程之(七)Shell输出这篇文章中 ...

  10. Arithmatic项目修改总结

    Arithmatic项目修改总结 github仓库 arithmatic3.0 一. 修改介绍 修改后类图: 1.关于类的合并 ==可以发现相比右边(旧)的类,左边(新)的类少了很多,这是我这次大改的 ...