LG3953 逛公园
题意
策策同学特别喜欢逛公园。公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从\(1\)号点进去,从\(N\)号点出来。
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果\(1\)号点 到\(N\)号点的最短路长为\(d\),那么策策只会喜欢长度不超过\(d+K\)的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对\(P\)取模。
如果有无穷多条合法的路线,请输出\(-1\)。
\(N \leq 100000,M \leq 200000,K \leq 50\)
分析
考虑dp。用\(f(x,lim)\)表示从x到n的路径长不超过dis(x,n)+lim的路径条数。
求出最短路后,就可以dfs求解,为了处理环的情况传进两个参数x和lim。
反向建图跑最短路可以优秀卡常,并且若跑完最短路后距离仍为INF就可以剪枝。
然后是无解的情况,如果有0环则有无数解。方法是SPFA或者dfs记录状态,若从某状态再次搜到相同的状态则肯定有0环。SPFA可能被卡,所以采用Dijkstra+dfs判0环的方法。
时间复杂度\(O(K M)\)
代码
dfs
中规中矩的记忆化搜索,是绝对的首选。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<cassert>
#include<stack>
#include<vector>
template<class T>T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return x=data*w;
}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int MAXN=1e5+7,MAXM=2e5+7,MAXK=60;
int n,m,k,mod;
vector <pii> g1[MAXN],g2[MAXN];
void init()
{
read(n);read(m);read(k);read(mod);
for(int i=1;i<=n;++i)
{
g1[i].clear();
g2[i].clear();
}
for(int i=1;i<=m;++i)
{
int x,y,w;
read(x);read(y);read(w);
g1[x].push_back(pii(y,w));
g2[y].push_back(pii(x,w));
}
}
int dis[MAXN];
void Dijkstra(int s)
{
fill(dis+1,dis+n+1,INF);
dis[s]=0;
priority_queue <pii> H;
H.push(pii(-dis[s],s));
while(H.size())
{
int x=H.top().second,d=-H.top().first;
H.pop();
if(d>dis[x])
continue;
for(int i=0;i<g2[x].size();++i)
{
int y=g2[x][i].first,w=g2[x][i].second;
if(dis[y]>dis[x]+w)
{
dis[y]=dis[x]+w;
H.push(pii(-dis[y],y));
}
}
}
}
int add(int x,int y)
{
x+=y;
return x>=mod?x-mod:x;
}
bool vis[MAXN][MAXK];
bool ins[MAXN][MAXK];
int f[MAXN][MAXK];
int dfs(int x,int lim)
{
// cerr<<"dfs "<<x<<" "<<lim<<endl;
if(vis[x][lim])
return f[x][lim];
if(ins[x][lim])
return -1;
ins[x][lim]=1;
int&ans=f[x][lim]=(x==n);
for(int i=0;i<g1[x].size();++i)
{
int y=g1[x][i].first,w=g1[x][i].second;
if(dis[y]==INF)
continue;
int delta=dis[y]+w-dis[x];
if(delta>lim)
continue;
int t=dfs(y,lim-delta);
if(t==-1)
return -1;
ans=add(ans,t);
}
vis[x][lim]=1;
ins[x][lim]=0;
return ans;
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
// freopen("park.err","w",stderr);
int T;
read(T);
while(T--)
{
init();
Dijkstra(n);
// cerr<<"dis="<<endl;
// for(int i=1;i<=n;++i)
// cerr<<i<<" d="<<dis[i]<<endl;
for(int i=1;i<=n;++i)
{
fill(vis[i],vis[i]+k+1,0);
fill(ins[i],ins[i]+k+1,0);
}
printf("%d\n",dfs(1,k));
}
return 0;
}
SPFA
要是用SPFA就要有信仰了,不可能入队n次才判0环,不然肯定TLE。
于是我逐渐去试,发现如果设成10会WA,设成11刚好能AC。出题人根本就没造网格图,但考试的时候谁又知道呢?
然后就跑得飞快。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
template<class T>T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return x=data*w;
}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int MAXN=1e5+7,MAXM=2e5+7,MAXK=60;
int n,m,k,mod;
struct edge // g2
{
int nx,to,w;
}e[MAXM];
int head[MAXN],ecnt;
vector <pii> g[MAXN]; // g1
void addedge(int x,int y,int w)
{
e[++ecnt].to=y,e[ecnt].w=w;
e[ecnt].nx=head[x],head[x]=ecnt;
}
void init()
{
read(n);read(m);read(k);read(mod);
ecnt=0;
fill(head+1,head+n+1,0);
for(int i=1;i<=n;++i)
g[i].clear();
for(int i=1;i<=m;++i)
{
int x,y,w;
read(x);read(y);read(w);
addedge(y,x,w);
g[x].push_back(pii(y,w));
}
}
bool inq[MAXN];
int cnt[MAXN];
int dis[MAXN];
bool SPFA(int s)
{
fill(inq+1,inq+n+1,0);
fill(cnt+1,cnt+n+1,0);
fill(dis+1,dis+n+1,INF);
dis[s]=0;
queue<int>Q;
Q.push(s);
inq[s]=1;
++cnt[s];
while(Q.size())
{
int x=Q.front();
Q.pop();
inq[x]=0;
for(int i=head[x];i;i=e[i].nx)
{
int y=e[i].to,w=e[i].w;
if(dis[y]>=dis[x]+w)
{
dis[y]=dis[x]+w;
if(!inq[y])
{
Q.push(y);
inq[y]=1;
if(++cnt[y]>=11) // 0 circle
return 0;
}
}
}
}
return 1;
}
int add(int x,int y)
{
x+=y;
return x>=mod?x-mod:x;
}
bool vis[MAXN][MAXK];
int f[MAXN][MAXK];
int dfs(int x,int lim)
{
// cerr<<"dfsing "<<x<<" lim="<<lim<<endl;
if(lim<0)
return 0;
if(vis[x][lim])
return f[x][lim];
int&ans=f[x][lim]=(x==n);
for(int i=0;i<g[x].size();++i)
{
int y=g[x][i].first,w=g[x][i].second;
if(!cnt[y]) // not accessible to n
continue;
int delta=dis[y]+w-dis[x];
ans=add(ans,dfs(y,lim-delta));
}
vis[x][lim]=1;
// cerr<<" ans="<<ans<<endl;
return ans;
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
// freopen("park.err","w",stderr);
int T;
read(T);
while(T--)
{
init();
if(!SPFA(n)) // 0 circle
{
puts("-1");
continue;
}
// cerr<<"dis="<<endl;
// for(int i=1;i<=n;++i)
// cerr<<i<<" d="<<dis[i]<<endl;
for(int i=1;i<=n;++i)
fill(vis[i],vis[i]+k+1,0);
printf("%d\n",dfs(1,k));
}
return 0;
}
Hint
注意数组范围。
LG3953 逛公园的更多相关文章
- 【图论 动态规划拆点】luoguP3953 逛公园
经典的动态规划拆点问题. 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 NN 个点 MM 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, NN 号点是公园的出口,每条边有一个非负 ...
- [vijos P1083] 小白逛公园
不知怎地竟有种错觉此题最近做过= =目测是类似的?那道题貌似是纯动归? 本来今晚想做两道题的,一道是本题,一道是P1653疯狂的方格取数或NOI08 Employee,看看现在的时间目测这个目标又达不 ...
- Bzoj 1756: Vijos1083 小白逛公园 线段树
1756: Vijos1083 小白逛公园 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1021 Solved: 326[Submit][Statu ...
- BZOJ 1756: Vijos1083 小白逛公园
题目 1756: Vijos1083 小白逛公园 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 856 Solved: 264[Submit][Sta ...
- JDOJ-P1260 VIJOS-P1083 小白逛公园
首先,在这里给大家推荐一个网站,https://neooj.com:8082,这是我母校的网站 言归正传,题目描述 VIJOS-P1083 小白逛公园 Time Limit: 1 Sec Memor ...
- [NOIP2017] 逛公园
[NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...
- [NOIp 2017]逛公园
Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- 【NOIP 2017】逛公园
Description 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要 ...
- 逛公园 [NOIP2017 D1T3] [记忆化搜索]
Description 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的 ...
随机推荐
- 可以,得驾证了\(^o^)/
说实在话,我自认为我不太适合开车. 首先我有点晕车,在车上坐久了就头晕脑胀. 心里素质也不行,凡是遇到什么事了,就慌慌张张,手忙脚乱. 然后就是练车一点都不稳,每次练车都会有新问题出现. 先说一下我科 ...
- php特级课---4、网站服务监控
php特级课---4.网站服务监控 一.总结 一句话总结:这些是架构师的知识 网络流量监控:cacti,mrtg 邮件报警系统:postfix 压力测试工具:Apache压力测试软件-ab,Mysql ...
- Hive 元数据库表信息
Hive 的元数据信息通常存储在关系型数据库中,常用MySQL数据库作为元数据库管理. 1. 版本表 i) VERSION -- 查询版本信息 2. 数据库.文件存储相关 i) DBS -- 存储 ...
- Android----- 改变图标原有颜色 和 搜索框
本博客主要讲以下两点知识点 图标改变颜色:Drawable的变色,让Android也能有iOS那么方便的图片色调转换,就像同一个图标,但是有多个地方使用,并且颜色不一样,就可以用这个方法了. 搜索框: ...
- VS2013 VC++的.cpp文件调用CUDA的.cu文件中的函数
CUDA 8.0在函数的调用中方便的让人感动.以下是从网上学到的VC++的.cpp文件调用CUDA的.cu文件中的函数方法,和一般的VC++函数调用的方法基本没差别. 使用的CUDA版本为CUDA 8 ...
- Ansible 小手册系列 十五(Blocks 分组)
当我们想在满足一个条件下,执行多个任务时,就需要分组了.而不再每个任务都要用when. tasks: - block: - command: echo 1 - shell: echo 2 - raw: ...
- 019——VUE中v-for与computer结合功能实例讲解
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- ffmpeg 命令小记
指定格式转码 ffmpeg -i 1.mp4 -c:v libx264 -c:a aac -y 1.flv 等时长转为m3u8格式 ffmpeg -i 1.avi -c:v libx264 -c:a ...
- poj3068
题解: 最小费用最大流 每一次找最短的 代码: #include<cstdio> #include<cmath> #include<cstring> #includ ...
- cf 915
t1:2分钟ac,简单模拟 t2:3发wa,最后再10分钟的时候过了 但是最后被hack了 t3:2发wa,最后还是被hack了 t4:拓扑排序 然后将一个点入度减一 然后是否能拓扑 t5:离散化+线 ...