【比赛】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]。

大体就是这样,剩下一些小细节就看代码吧。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN=100000+10,MAXM=200000+10,MAXK=60+10,inf=0x3f3f3f3f;
  4 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];
  5 inline void read(int &x)
  6 {
  7     int data=0,w=1;
  8     char ch=0;
  9     while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
 10     if(ch==‘-‘)w=-1,ch=getchar();
 11     while(ch>=‘0‘&&ch<=‘9‘)data=(data<<3)+(data<<1)+(ch^‘0‘),ch=getchar();
 12     x=data*w;
 13 }
 14 inline void chksum(int &a,int b)
 15 {
 16     a+=b;
 17     if(a>Mod)a-=Mod;
 18 }
 19 inline void insert(int x,int y,int z)
 20 {
 21     to[++e]=y;
 22     nex[e]=beg[x];
 23     beg[x]=e;
 24     w[e]=z;
 25     qto[++qe]=x;
 26     qnex[qe]=qbeg[y];
 27     qbeg[y]=qe;
 28     qw[qe]=z;
 29 }
 30 inline void init()
 31 {
 32     e=0;
 33     memset(beg,0,sizeof(beg));
 34     qe=0;
 35     memset(qbeg,0,sizeof(qbeg));
 36     memset(f,0,sizeof(f));
 37     cnt=0;
 38     memset(Indegree,0,sizeof(Indegree));
 39 }
 40 inline void SPFA()
 41 {
 42     queue<int> q;
 43     for(register int i=1;i<=n;++i)dis1[i]=inf,p[i]=0;
 44     q.push(1);
 45     p[1]=1;
 46     dis1[1]=0;
 47     while(!q.empty())
 48     {
 49         int x=q.front();
 50         q.pop();
 51         p[x]=0;
 52         for(register int i=beg[x];i;i=nex[i])
 53             if(dis1[to[i]]>dis1[x]+w[i])
 54             {
 55                 dis1[to[i]]=dis1[x]+w[i];
 56                 if(!p[to[i]])
 57                 {
 58                     p[to[i]]=1;
 59                     q.push(to[i]);
 60                 }
 61             }
 62     }
 63     for(register int i=1;i<=n;++i)dis2[i]=inf,p[i]=0;
 64     q.push(n);
 65     p[n]=1;
 66     dis2[n]=0;
 67     while(!q.empty())
 68     {
 69         int x=q.front();
 70         q.pop();
 71         p[x]=0;
 72         for(register int i=qbeg[x];i;i=qnex[i])
 73             if(dis2[qto[i]]>dis2[x]+qw[i])
 74             {
 75                 dis2[qto[i]]=dis2[x]+qw[i];
 76                 if(!p[qto[i]])
 77                 {
 78                     p[qto[i]]=1;
 79                     q.push(qto[i]);
 80                 }
 81             }
 82     }
 83 }
 84 inline void toposort()
 85 {
 86     queue<int> q;
 87     for(register int x=1;x<=n;++x)
 88         for(register int i=beg[x];i;i=nex[i])
 89             if(dis1[to[i]]==dis1[x]+w[i])Indegree[to[i]]++;
 90     for(register int i=1;i<=n;++i)
 91         if(!Indegree[i])q.push(i),topoorder[++cnt]=i;
 92     while(!q.empty())
 93     {
 94         int x=q.front();
 95         q.pop();
 96         for(register int i=beg[x];i;i=nex[i])
 97             if(dis1[to[i]]==dis1[x]+w[i])
 98             {
 99                 Indegree[to[i]]--;
100                 if(!Indegree[to[i]])q.push(to[i]),topoorder[++cnt]=to[i];
101             }
102     }
103 }
104 inline void DP()
105 {
106     f[1][0]=1;
107     for(register int j=0;j<=k;++j)
108     {
109         for(register int p=1;p<=cnt;++p)
110         {
111             int x=topoorder[p];
112             for(register int i=beg[x];i;i=nex[i])
113                 if(dis1[to[i]]==dis1[x]+w[i])chksum(f[to[i]][j],f[x][j]);
114         }
115         for(register int x=1;x<=n;++x)
116             for(register int i=beg[x];i;i=nex[i])
117                 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]);
118     }
119 }
120 int main()
121 {
122     freopen("park.in","r",stdin);
123     freopen("park.out","w",stdout);
124     int T;
125     read(T);
126     while(T--)
127     {
128         init();
129         read(n);read(m);read(k);read(Mod);
130         int mark=0;
131         for(register int i=1;i<=m;++i)
132         {
133             int u,v,w;
134             read(u);read(v);read(w);
135             insert(u,v,w);
136         }
137         SPFA();
138         toposort();
139         for(register int i=1;i<=n;++i)
140             if(Indegree[i]&&dis1[i]+dis2[i]<=dis1[n]+k)
141             {
142                 printf("-1\n");
143                 mark=1;
144                 break;
145             }
146         if(mark)continue;
147         DP();
148         int ans=0;
149         for(register int i=0;i<=k;++i)chksum(ans,f[n][i]);
150         printf("%d\n",ans);
151     }
152     return 0;
153 }

NOIP2017 逛公园

时间: 2024-08-01 15:22:22

【比赛】NOIP2017 逛公园的相关文章

[NOIP2017] 逛公园

[NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^5\) 题目解法 两个月后再看也不是太难,自己就能独立思考出来. 首先是判-1的问题,显然能产生-1的只有0环. 所以把0环都找出来, 然后检查一下\(dis[\)\(1\),环\(]\) + \(dis[\)环,\(n]\) 是否小于等于 \(dis[1,n]+K\)即可. 如果不是无限路径的话,

Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线. 策策

P3953 NOIP2017 d1t3 逛公园

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN 个点MM 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN 号点的最短路长为dd ,那么策策只会喜欢长度不超过d + Kd+K 

luogu 3953 逛公园

noip2017 D1T3 逛公园 某zz选手看到数据范围直接就最短路计数了,结果写错了爆零 题目大意: N个点M条边构成的有向图,且没有自环和重边.其中1号点是起点,N号点是公园的终点,每条边有一个非负权值, 代表经过这条边所要花的时间 如果1号点到N号点的最短路长为d,那么策策只选择长度不超过d + K的路线 求总共有多少条满足条件的路线 为避免输出过大,答案对P取模. 如果有无穷多条合法的路线,请输出?1 思路: 首先需要求出最短路用spfa 然后我们dfs的时候dp 具体见注释 1 #i

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

P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从 \(1\) 号点进去,从 \(N\) 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果 \(

TYVJ1427 小白逛公园

P1427 小白逛公园 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了.    一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的一些公园玩.小白当然希望选出的公园的分数总和尽量高咯

线段树--小白逛公园nkoj1316

小白逛公园 Time Limit:20000MS  Memory Limit:65536K Case Time Limit:2000MS Description 小新经常陪小白去公园玩,也就是所谓的遛狗啦-在小新家附近有一条"公园路",路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的

NOIP2017D1T3逛公园——哎呦!

#include<cstdio> #include<cstring> #define MXN 100001 #define MXM 200001 #define MXK 51 int afst[MXM],anxt[MXM],av[MXM],aw[MXM]; int bfst[MXM],bnxt[MXM],bv[MXM],bw[MXM]; int dis[MXN],queue[10*MXN]; int f[MXN][MXK],vis[MXN][MXK]; int n,m,k,p,t,

[NOIp 2017]逛公园

Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从$N$号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到$N$号点的最短路长为$d$,那么策策只会喜欢长度不超过$d