noip2017逛公园
题解:
之前知道正解并没有写过。。
#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
#define me(x) memset(x,0,sizeof(x))
char ss[<<],*A=ss,*B=ss;
IL char gc()
{
return A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++;
}
template<class T>void read(T &x)
{
rint f=,c; while (c=gc(),c<||c>) if (c=='-') f=-; x=(c^);
while (c=gc(),c>&&c<) x=(x<<)+(x<<)+(c^); x*=f;
}
const int N=3e5;
struct re{
int a,b,c;
}e[N],jl[N];
int n,m,k,p,head[N],l,rd[N],tim[N];
void arr(int x,int y,int z)
{
e[++l].a=head[x];
e[l].b=y;
e[l].c=z;
head[x]=l;
}
queue<int> q;
stack<int> S;
int dfn[N],low[N],col[N],color_cnt,sz[N],cnt,tim2[N];
bool ins[N];
void tarjan(int x,int y)
{
dfn[x]=low[x]=++cnt; S.push(x); ins[x]=;
for (rint u=head[x];u;u=e[u].a)
{
rint v=e[u].b;
if (!dfn[v])
{
tarjan(v,x);
dfn[x]=min(dfn[x],low[v]);
}
if (ins[v]) dfn[x]=min(dfn[x],dfn[v]);
}
if (dfn[x]==low[x])
{
color_cnt++;
while ()
{
int y=S.top(); S.pop(); col[y]=color_cnt; ins[y]=; sz[color_cnt]++;
if (y==x) break;
}
}
}
const int INF=5e8;
int dis[N],dis1[N],dis2[N];
struct cmp{
bool operator () (re x,re y)
{
return x.b>y.b;
}
};
priority_queue<re,vector<re>,cmp> Q;
bool vis[N];
void dij(int x)
{
me(vis);
rep(i,,n) dis[i]=INF;
Q.push((re){x,}); dis[x]=;
while (!Q.empty())
{
int x=Q.top().a; Q.pop();
if (vis[x]) continue; vis[x]=;
for (rint u=head[x];u;u=e[u].a)
{
int v=e[u].b;
if (dis[v]>dis[x]+e[u].c)
{
dis[v]=dis[x]+e[u].c;
Q.push((re){v,dis[v]});
}
}
}
}
int f[N][];
const int N2=1.5e7;
re ve[N2];
IL void js(int &x,int y)
{
x=(x+y)%p;
}
bool cmp3(re y,re x)
{
int jl1=dis1[x.a]+x.b;
int jl2=dis1[y.a]+y.b;
return (jl2<jl1)||(jl1==jl2&&tim[y.a]<tim[x.a]);
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int T;
read(T);
rep(ttt,,T)
{
l=; me(head); me(dfn); me(low); me(sz); color_cnt=;
read(n); read(m); read(k); read(p); me(rd);
rep(i,,m)
{
int x,y,z;
read(x); read(y); read(z);
jl[i]=(re){x,y,z};
if (z==) arr(x,y,z),rd[y]++;
}
rep(i,,n) if (!rd[i]) q.push(i);
int cnt=;
while (!q.empty())
{
int x=q.front(); q.pop(); tim[x]=++cnt;
for (rint u=head[x];u;u=e[u].a)
{
rint v=e[u].b;
rd[v]--;
if (!rd[v]) q.push(v);
}
}
rep(i,,n) if (!dfn[i]) tarjan(i,);
me(head); l=;
int s=col[],t=col[n];
rep(i,,m)
if (col[jl[i].a]!=col[jl[i].b]) arr(col[jl[i].a],col[jl[i].b],jl[i].c);
dij(s);
rep(i,,n) dis1[i]=dis[i];
me(head); l=;
rep(i,,m)
if (col[jl[i].a]!=col[jl[i].b]) arr(col[jl[i].b],col[jl[i].a],jl[i].c);
dij(t);
rep(i,,n) dis2[i]=dis[i];
int now=dis1[n];
bool tt=;
rep(i,,color_cnt)
if (dis1[i]+dis2[i]<=now+k&&sz[i]>) tt=;
if (tt)
{
cout<<-<<endl;
continue;
}
me(head); l=;
rep(i,,m)
if (col[jl[i].a]!=col[jl[i].b]) arr(col[jl[i].a],col[jl[i].b],jl[i].c);
int ans=;
me(f);
f[s][]=;
rep(i,,n) tim2[col[i]]=tim[i];
rep(i,,n) tim[i]=tim2[i];
int cnt2=;
rep(i,,color_cnt)
rep(j,,)
if (dis1[i]+dis2[i]+j<=now+k)
{
ve[++cnt2]=(re){i,j};
}
sort(ve+,ve+cnt2+,cmp3);
rep(i,,cnt2)
{
re xx=ve[i];
int x=xx.a,y=xx.b;
if (!f[x][y]) continue;
if (x==t) ans=(ans+f[x][y])%p;
for (rint u=head[x];u;u=e[u].a)
{
rint v=e[u].b;
if (e[u].c+y+dis1[x]+dis2[v]<=now+k)
{
int t1=f[v][e[u].c+y+dis1[x]-dis1[v]],t2=f[x][y];
js(t1,t2);
f[v][e[u].c+y+dis1[x]-dis1[v]]=t1;
}
}
}
cout<<ans<<endl;
}
return ;
}
我觉得这细节真的挺多的。。
而且我都不知道我去年怎么写的60分了。。
网上的方法好像比我的简单。。。
首先在0环上我的处理是
先缩点,然后判缩完后的点能否在路径上
如果能在,输出-1
由于这个缩点还是带来了比较大的干扰。。
调试中的几个错都是这个产生的。。
另外最短路据说是线段树优化跑的最快??
最后的dp还是比较简单的
f[i][j]表示到i点,比原先最短路长j,然后对终点跑一遍最短路来剪枝
然后发现相同dis可以互相转移
所以根据零边拓扑排序一下
网上的判0环的方法比较简单
直接在做的时候 如果扩展到之前的状态 就说明有0环
这很显然啊。。。。
主要刚开始没仔细想这个过程。。
noip至少得留1:30 才能搞完这题吧。。 2:00就比较稳
诶网上最简单的代码好简单啊。。。
直接对s跑一遍最短路,然后直接dp 省掉所有过程啊 而且还挺快的。。。(看来这个剪枝作用也不是很大)
所以下次还是想清楚再写。。。 看看有没有简单的办法
要是写后面这份代码 1小时足够了啊。。。
noip2017逛公园的更多相关文章
- [NOIP2017] 逛公园
[NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...
- 【比赛】NOIP2017 逛公园
考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在 ...
- 【题解】NOIP2017逛公园(DP)
[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...
- NOIP2017逛公园(dp+最短路)
策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会 ...
- NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】
题目描述 策策同学特别喜欢逛公园.公园可以看成一张NNN个点MMM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花 ...
- [NOIP2017]逛公园 题解
我连D1T3都不会我联赛完蛋了 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 N 个点 M 条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口, N 号点是公园的出口,每条边有一个非负 ...
- [NOIP2017] 逛公园 解题报告(DP)
我很不想说 在我的AC代码上我打了表,但实在没有办法了.莫名的8,9个点RE.然而即便是打表...也花了我很久. 这大概是NOIP2017最难的题了,为了让不懂的人更容易理解,这篇题解会比较详细 我的 ...
- [NOIP2017] 逛公园 【最短路】【强连通分量】
题目分析: 首先考虑无数条的情况.出现这种情况一定是一条合法路径经过了$ 0 $环中的点.那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离.加起来若离最短路径不超过$ k $则输出$ ...
- luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)
先跑一边dijkstra算出从1到i的最短距离dis[i] 然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数 答案就是$\sum\limits_{i=0}^{k} ...
随机推荐
- requests库入门06-post请求
示例相应的接口文档:GitHub邮箱接口文档 先登录GitHub,然后右上角用户下拉框中选择settings,然后选Emails.可以看到当前账户设置的邮箱情况 再看添加邮箱接口的文档描述,可以通过一 ...
- Android App签名打包
Andriod应用程序如果要在手机或模拟器上安装,必须要有签名! 1.签名的意义 为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序 ...
- Django请求周期图
- CentOS7安装和配置MySQL
1. 下载MySQL Yum Repository http://dev.mysql.com/downloads/repo/yum/ 2. 本地安装MySQL Yum Repository s ...
- 4)django-视图view
视图是django功能函数,结合url使用 1.视图方式 视图方式经常用的有两种 用户GET获取数据 用户POST提交数据 用户第一次访问页面是GET 用户 ...
- 4)协程一(yeild)
一:什么协程 协程: coroutine/coro - 轻量级线程(一个线程) - 调度由用户控制 - 有独立的寄存器上下文和栈 - 切换时保存状态,回来时恢复 二:协程和多线程比较 协程: coro ...
- kindeditor用法简单介绍(转)
1,首先去官网下载http://www.kindsoft.net/ 2,解压之后如图所示: 由于本人做的是用的是JSP,所以ASP,PHP什么的就用不上了,直接把那些去掉然后将整个文件夹扔进Myecl ...
- 体验go语言的风骚式编程
最近想搞搞后台开发,话说注意力就转移到了公司用的golang.用Go做微服务比较方便,或许是因为golang强悍的语法吧,看到go的语法,自己已被深深的吸引.关于学习后台如何选择可以参考<做后台 ...
- swift 学习- 27 -- 访问控制
// 访问控制 可以限定其源文件 或模块中的代码对你的代码的访问级别, 这个特性可以让我们隐藏代码的一些实现细节, 并且可以为其他人可以访问和使用的代码提供接口 // 你可以明确地给某个类型 (类, ...
- 瑞联科技:Pwp3框架 调用存储过程返还数据集合 到前端界面展示
一:代码结构: 1:Js 代码结构 2:Java 代码结构 二:前端界面展示效果 为了数据安全性:界面数据做了处理 三:全端代码展示 1:main.vop <html> <head& ...