不管怎么说,这都是一道十分神仙的NOIp题

你可以说它狗,但不可以否认它就是NOIp的难度

首先这道题很显然是道图论题还是一道图论三合一(最短路+拓扑+图上DP)

先考虑最短路,我们分别以\(1\)和\(n\)为起点得出与其它点的最短路(虽然NOIp应该不会卡SPFA,但还是建议写稳定的DJ)

我们先考虑把\(-1\)的情况给判掉,分析一下发现此时必定有0环(此时可以在0环上无限刷路径)

但是要注意一下,当且仅当0环上的任意一点\(i\)到\(1\)的最短路\(dis_{1,i}\)以及它到\(n\)的最短路\(dis_{i,n}\)满足\(dis_{1,i}+dis_{i,n}<=dis_{1,n}+k\),因为这个0环首先得在可行路径上

处理0环的具体操作只要把0边权的边单独拎出来做拓扑排序就好了。

然后考虑如何统计答案,我们发现\(k<=50\)。因此我们图上DP计数

设\(f_{i,j}\)表示到第\(i\)个点时,偏移量(偏移量为当前路径长度与\(dis_{1,i}\)的差)为\(j\)的方案数:

我们再枚举\(i\)可以到达的点\(p\),若\(dis_{1,i}+w+j-dis_{1,p}<=k\),然后就可以用\(f_{i,j}\)更新\(f_{p,dis_{1,i}+w+j-dis_{1,p}}\)了(\(w\)为\(i\rightarrow p\)的边权)

最后要注意的是枚举的状态顺序,我们发现对于所有的点\(i\),当它的\(dis_{1,i}\)越小时,它越早更新

特别地,当都是0权的边排序时,应该按之前的拓扑顺序排

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=100005,K=55;
struct edge
{
int to,next,v;
}e[N<<1],re[N<<1];
struct Zero_edge
{
int to,next;
}ze[N<<1];
struct Small
{
int num,s;
bool operator <(const Small x) const { return x.s<s; }
};
struct data
{
int d,id,num;
}a[N];
int head[N],rhead[N],zhead[N],t,n,m,k,p,x,y,z,cnt,zcnt,ru[N],q[N],f[N][K],dis[N],INF,r[N];
bool vis[N];
priority_queue <Small> small;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+'0');
}
inline void clear(void)
{
memset(head,-1,sizeof(head)); memset(rhead,-1,sizeof(rhead));
memset(zhead,-1,sizeof(zhead)); memset(ru,0,sizeof(ru)); cnt=zcnt=0;
}
inline void add(int x,int y,int z)
{
e[++cnt].to=y; e[cnt].next=head[x]; e[cnt].v=z; head[x]=cnt;
}
inline void radd(int x,int y,int z)
{
re[cnt].to=y; re[cnt].next=rhead[x]; re[cnt].v=z; rhead[x]=cnt;
}
inline void zadd(int x,int y)
{
ze[++zcnt].to=y; ze[zcnt].next=zhead[x]; zhead[x]=zcnt; ++ru[y];
}
inline void top_sort(void)
{
register int i,H=0,T=0;
for (i=1;i<=n;++i)
{
if (!ru[i]) q[++T]=i,a[i].id=T; a[i].num=i;
}
while (H<T)
{
int now=q[++H];
for (i=zhead[now];~i;i=ze[i].next)
if (!(--ru[ze[i].to])) q[++T]=ze[i].to,a[ze[i].to].id=T;
}
}
inline void front_dijkstra(void)
{
memset(dis,63,sizeof(dis)); memset(vis,0,sizeof(vis));
small.push((Small){1,0}); INF=dis[0]; dis[1]=a[1].d=0;
while (!small.empty())
{
int now=small.top().num; small.pop();
if (vis[now]) continue; vis[now]=1;
for (register int i=head[now];~i;i=e[i].next)
if (dis[e[i].to]>dis[now]+e[i].v)
{
a[e[i].to].d=dis[e[i].to]=dis[now]+e[i].v;
small.push((Small){e[i].to,dis[e[i].to]});
}
}
}
inline void back_dijkstra(void)
{
memset(dis,63,sizeof(dis)); memset(vis,0,sizeof(vis));
small.push((Small){n,0}); dis[n]=0;
while (!small.empty())
{
int now=small.top().num; small.pop();
if (vis[now]) continue; vis[now]=1;
for (register int i=rhead[now];~i;i=re[i].next)
if (dis[re[i].to]>dis[now]+re[i].v)
{
dis[re[i].to]=dis[now]+re[i].v;
small.push((Small){re[i].to,dis[re[i].to]});
}
}
}
inline bool check(void)
{
for (register int i=1;i<=n;++i)
if (ru[i]&&a[i].d+dis[i]<=a[n].d+k) return 1;
return 0;
}
inline bool cmp(data a,data b)
{
if (a.d<b.d) return 1;
if (a.d>b.d) return 0;
return a.id<b.id;
}
inline void inc(int &x,int y)
{
if ((x+=y)>=p) x-=p;
}
inline int DP(void)
{
memset(f,0,sizeof(f)); f[1][0]=1; int ans=0;
for (register int s=0;s<=k;++s)
{
for (register int i=1;i<=n;++i)
{
int now=a[i].num;
for (register int j=head[now];~j;j=e[j].next)
if (a[i].d+s+e[j].v-a[r[e[j].to]].d<=k)
inc(f[e[j].to][a[i].d+s+e[j].v-a[r[e[j].to]].d],f[now][s]);
}
inc(ans,f[n][s]);
} return ans;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(t);
while (t--)
{
read(n); read(m); read(k); read(p); clear();
for (i=1;i<=m;++i)
{
read(x); read(y); read(z);
add(x,y,z); radd(y,x,z); if (!z) zadd(x,y);
}
top_sort(); front_dijkstra(); back_dijkstra();
if (check()) { puts("-1"); continue; } sort(a+1,a+n+1,cmp);
for (i=1;i<=n;++i) r[a[i].num]=i;
write(DP()); putchar('\n');
}
return 0;
}

Luogu P3953 逛公园的更多相关文章

  1. [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...

  2. Luogu P3953 逛公园(最短路+记忆化搜索)

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

  3. 【luogu P3953 逛公园】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...

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

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

  5. luogu 3953 逛公园

    noip2017 D1T3 逛公园 某zz选手看到数据范围直接就最短路计数了,结果写错了爆零 题目大意: N个点M条边构成的有向图,且没有自环和重边.其中1号点是起点,N号点是公园的终点,每条边有一个 ...

  6. LOJ P3953 逛公园 NOIP dp 最短路 拓扑排序

    https://www.luogu.org/problemnew/show/P3953 开o2过了不开o2re一个点...写法如题 顺便一提这道题在我校oj是a不了的因为我校土豆服务器速度奇慢1s时限 ...

  7. 洛谷P3953逛公园

    题目 作为\(NOIp2017D1T3\) 这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧. 这个题可以作为记忆化搜索的进阶题了,做这个题的方法也 ...

  8. P3953 逛公园

    传送门 花了一个下午才 A 的毒瘤题 思路: 这题需要建两个图,一个正向图,一个反向图. 先在正向图上跑一遍 dijkstar ,计算出每个点到 点1 的最短路径 . 然后在反向图上开始记忆化搜索: ...

  9. 洛谷 P3953 逛公园

    题目链接 思路 首先没有0边,且k为0的情况就是最短路计数. 如果k不为0,看到k<=50,想到dp. 设f[u][i]表示到达u点比最短路多走i的路径数,转移到v点. f[u][i]+=f[v ...

随机推荐

  1. Python 基于python+mysql浅谈redis缓存设计与数据库关联数据处理

    基于python+mysql浅谈redis缓存设计与数据库关联数据处理 by:授客  QQ:1033553122 测试环境 redis-3.0.7 CentOS 6.5-x86_64 python 3 ...

  2. 超简单,Centos7 安装 rabbitMQ

    首先声明,本人是Linux新手一枚.经历了在阿里云Centos上部署rabbitMQ与重装的痛苦经历,后多方查找终于找到了简单方法.Linux高人来说请跳过本篇文章,新手可以试试. 1.设置Cento ...

  3. FUSE 文件系统 example部分 源码注释 (libfuse 2.9.9)

    本篇文章主要是针对fuse-2.9.9 Example 部分 给出的源码,结合官方文档,以及网上的资料给出注释,希望能给正在学习的你们一点帮助. Hello.c /* FUSE: Filesystem ...

  4. python3 下列表与字典转换

    在写爬虫的时候,经常需要处理cookie,requests库里的cookie是dict,但是headers['cookie']却是一个key=value的字符串. 下面是几个用推导式实现的转换函数,供 ...

  5. Win10更换电脑,又不想重装系统的解决方法

    问题描述: 在公司因为两年前用的i3的电脑很卡,然后想换i5的电脑,但是又不想重装系统,因为安装的东西太多了,重装很麻烦 Windows to go介绍: Windows To Go是Windows ...

  6. vue-cli在控制台创建vue项目时乱码的问题

    新装的win10系统,使用vue-cli在控制台创建项目时出现乱码,请问如何处理? 解决: 打开cmd,在控制台输入CHCP 65001,按回车键即可将编码格式设成utf-8,再创建就不会乱码了. 执 ...

  7. VMware NAT 设置原理

    1.网络地址转换(NAT):默认使用VMnet8 (强烈推荐) 这种访问模式指的是虚拟机不占用主机所在局域网的ip,通过使用主机的NAT功能访问局域网和互联网,意味着虚拟机可以访问局域网中的其他电脑, ...

  8. UG/NX 8.0安装方法(图文详解)

    UG8.0,自从被西门子收购后改名为NX,也称NX8.0,作为一款非常优秀三维模具设计软件.他可以针对用户的虚拟产品设计和工艺设计的需求,提供经过实践验证的解决方案.其以全面的设计概念.良好的界面受到 ...

  9. Vue表单修饰符(lazy,number,trim)

    lazy:使用了这个修饰符将会从“input事件”变成change事件进行同步 <div id="example"> <input type="text ...

  10. 转:git合并冲突解决方法

    git合并冲突解决方法 1.git merge冲突了,根据提示找到冲突的文件,解决冲突 如果文件有冲突,那么会有类似的标记 2.修改完之后,执行git add 冲突文件名 3.git commit注意 ...