NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序
原文链接https://www.cnblogs.com/zhouzhendong/p/9258043.html
题目传送门 - 洛谷P3953
题目传送门 - Vijos P2030
题意
给定一个有向图,有 $n$ 个节点 $m$ 条边,边权值 $\in[0,1000]$ 。
小明要从 $1$ 走到 $n$ ,要求路径长度最大为 $d+k$ ,其中 $d$ 为 $1$ 到 $n$ 最短路长度。
问小明有多少种走法,答案对 $p$ 取模。如果有无数种走法,那么输出 $-1$ 。
$n\leq 100000,m\leq 200000,0\leq k\leq 50,1\leq p \leq 10^9$
题解
我们首先看看没有 $0$ 边,即答案不为 $-1$ 的情况。
显然我们可以先 SPFA 跑一遍最短路。
我们记 $dis_i$ 表示到节点 $i$ 的最短路长度。
令 $dp_{i,j}$ 表示到达第 $i$ 个节点,路径长度为 $dis_i+j$ 的路径个数。
显然可以在最短路网上生成的最短路 DAG 上搞一个拓扑序,然后 $\Theta(nk)$ DP 解决。
那么如果出现了 $0$ 环呢?
首先我们不能草率的定下“图中有 $0$ 环答案就是 $-1$”这种结论。
当然,“ $1$ 至 $n$ 通路上有零环答案是 $-1$” 也是错的。
考虑到 $0$ 环上面可以随意转移,所以同一个 $0$ 环上的节点就像一个节点一样。
所以我们可以 Tarjan 缩点一波。具体地:如果边权为 $0$ ,那么视为有边,否则视为无边。强连通缩点建立新图。
于是我们在新环上面做 DP 。
考虑在 DP 的过程中,一旦遇到零环上的点 $i$ ,一旦 $dp_{i,j}>0$ ,那么 $dp_{i,j}=\infty$ 。
并用此更新后面的点。
这里需要注意一个细节:由于我们计算的 $dp_{i,j}$ 是模意义下的,当 $dp_{i,j}\equiv 0\pmod p$ 时,不一定满足 $dp_{i,j}=0$,所以我们需要再开一个数组来记录 $dp_{i,j}$ 的特性:是 $0$ 、有限正整数 还是 $\infty$ 。
然后我 TLE 了……蒟蒻自带大常数啊 QAQ ,只能卡常了。
搞了好久之后,才想到好的做法。由于数组模拟链表跳着访问数组会很慢的,所以:
可以通过把要访问的边按照顺序放在连续的存储单元内,并顺序访问来提高速度。
结果卡了两倍多的常数,过掉了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100005,M=N*2,K=55;
int T,n,m,k,p;
int read(){
int x=0;
char ch=getchar();
while (!('0'<=ch&&ch<='9'))
ch=getchar();
while ('0'<=ch&&ch<='9')
x=(x<<1)+(x<<3)+ch-48,ch=getchar();
return x;
}
struct Gragh{
int cnt,x[M],y[M],z[M],nxt[M],fst[N];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,int c){
y[++cnt]=b,x[cnt]=a,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g,g2;
int Time,top,tot,bh[N],dfn[N],low[N],vis[N],st[N],inst[N],Nodecnt[N];
int dp[N][K],type[N][K];
int X[M],Y[M],Z[M],e;
void Tarjan(int x){
vis[x]=1,dfn[x]=low[x]=++Time;
st[++top]=x,inst[x]=1;
for (int i=g.fst[x];i;i=g.nxt[i]){
if (g.z[i]>0)
continue;
int y=g.y[i];
if (!vis[y]){
Tarjan(y);
low[x]=min(low[x],low[y]);
}
else if (inst[y])
low[x]=min(low[x],low[y]);
}
if (dfn[x]==low[x]){
tot++;
bh[st[top]]=tot;
inst[st[top]]=0;
while (st[top--]!=x){
bh[st[top]]=tot;
inst[st[top]]=0;
}
}
}
int q[N],head,tail,qmod,dis[N],f[N],in[N];
void SPFA(int S){
memset(f,0,sizeof f);
for (int i=0;i<N;i++)
dis[i]=1.5e9;
head=tail=0,qmod=tot+2;
dis[S]=0,f[S]=1,q[++tail]=S;
while (head!=tail){
int x=q[head=(head+1)%qmod],y;
f[x]=0;
for (int i=g2.fst[x];i;i=g2.nxt[i])
if (dis[y=g2.y[i]]>dis[x]+g2.z[i]){
dis[y]=dis[x]+g2.z[i];
if (!f[y]){
f[y]=1;
q[tail=(tail+1)%qmod]=y;
}
}
}
}
void solve(){
n=read(),m=read(),k=read(),p=read();
int S=1,T=n;
g.clear();
for (int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
g.add(a,b,c);
}
Time=top=tot=0;
memset(bh,0,sizeof bh);
memset(st,0,sizeof st);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(vis,0,sizeof vis);
memset(inst,0,sizeof inst);
for (int i=1;i<=n;i++)
if (!vis[i])
Tarjan(i);
g2.clear();
for (int i=1;i<=g.cnt;i++)
if (bh[g.x[i]]!=bh[g.y[i]])
g2.add(bh[g.x[i]],bh[g.y[i]],g.z[i]);
memset(Nodecnt,0,sizeof Nodecnt);
for (int i=1;i<=n;i++)
Nodecnt[bh[i]]++;
S=bh[S],T=bh[T];
SPFA(S);
memset(in,0,sizeof in);
for (int i=1;i<=g2.cnt;i++)
if (dis[g2.x[i]]+g2.z[i]==dis[g2.y[i]])
in[g2.y[i]]++;
head=tail=0;
for (int i=1;i<=tot;i++)
if (in[i]==0)
q[++tail]=i;
while (head<tail){
int x=q[++head],y;
for (int i=g2.fst[x];i;i=g2.nxt[i])
if (dis[x]+g2.z[i]==dis[g2.y[i]]){
in[g2.y[i]]--;
if (in[g2.y[i]]==0)
q[++tail]=g2.y[i];
}
}
memset(type,0,sizeof type);
memset(dp,0,sizeof dp);
dp[S][0]=type[S][0]=1;
int ans=0;
e=0;
for (int iq=1;iq<=tot;iq++)
for (int i=g2.fst[q[iq]];i;i=g2.nxt[i]){
e++;
X[e]=g2.x[i];
Y[e]=g2.y[i];
Z[e]=g2.z[i];
}
for (int ix=0;ix<=k;ix++){
int x,y,z;
for (int i=1;i<=tot;i++)
if (Nodecnt[i]>1&&type[i][ix]==1)
type[i][ix]=2;
for (int i=1;i<=e;i++){
x=X[i],y=Y[i],z=Z[i];
if (type[x][ix]==0)
continue;
int iy=dis[x]+ix+z-dis[y];
if (iy>k||type[y][iy]==2)
continue;
type[y][iy]=type[x][ix];
if (type[x][ix]==1){
dp[y][iy]=dp[y][iy]+dp[x][ix];
if (dp[y][iy]>=p)
dp[y][iy]-=p;
}
}
if (type[T][ix]==2){
ans=-1;
break;
}
else if (type[T][ix]==1)
ans=(ans+dp[T][ix])%p;
}
printf("%d\n",ans);
}
int main(){
T=read();
while (T--)
solve();
return 0;
}
NOIP2017提高组Day1T3 逛公园 洛谷P3953 Tarjan 强连通缩点 SPFA 动态规划 最短路 拓扑序的更多相关文章
- 【题解】洛谷P3953 [NOIP2017TG] 逛公园(记忆化搜索+SPFA)
题目来源:洛谷P3953 思路 先用SPFA求一遍最短路 在求最短路的同时可以把所有点到终点的最短路求出来 dis数组 注意要反向SPFA 因为从起点开始可能会走到一些奇怪的路上导致时间负责度增加 ...
- [NOIp2017提高组]列队
[NOIp2017提高组]列队 题目大意 一个\(n\times m(n,m\le3\times10^5)\)的方阵,每个格子里的人都有一个编号.初始时第\(i\)行第\(j\)列的编号为\((i-1 ...
- JZOJ 5196. 【NOIP2017提高组模拟7.3】B
5196. [NOIP2017提高组模拟7.3]B Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits Goto Pro ...
- JZOJ 5197. 【NOIP2017提高组模拟7.3】C
5197. [NOIP2017提高组模拟7.3]C Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits Goto Pro ...
- JZOJ 5195. 【NOIP2017提高组模拟7.3】A
5195. [NOIP2017提高组模拟7.3]A Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits Goto Pro ...
- JZOJ 5184. 【NOIP2017提高组模拟6.29】Gift
5184. [NOIP2017提高组模拟6.29]Gift (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB Detailed ...
- JZOJ 5185. 【NOIP2017提高组模拟6.30】tty's sequence
5185. [NOIP2017提高组模拟6.30]tty's sequence (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB ...
- NOIP2017提高组 模拟赛15(总结)
NOIP2017提高组 模拟赛15(总结) 第一题 讨厌整除的小明 [题目描述] 小明作为一个数学迷,总会出于数字的一些性质喜欢上某个数字,然而当他喜欢数字k的时候,却十分讨厌那些能够整除k而比k小的 ...
- NOIP2017提高组 模拟赛13(总结)
NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...
随机推荐
- Laravel 怎么在 blade 视图中将带 HTML 字符原样输出
### 感觉这是比较细小的,细节处理问题,很容易就一下子想不起怎么处理 但知道处理方式是那么简单时,真的觉得基础不够扎实 ### 富文本编辑内容: 视图原样输出: 视图模板的标签是这样处理就可以的-- ...
- cocos2dx-lua 延迟调用函数和定时器
下面是cocos官方的方法. function performWithDelay(node, callback, delay) local delay = cc.DelayTime:create(de ...
- linux计算服务器最近一次重启的时间
date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y-%m-%d %H:%M:%S" 这 ...
- 大数据mapreduce俩表join之python实现
二次排序 在Hadoop中,默认情况下是按照key进行排序,如果要按照value进行排序怎么办?即:对于同一个key,reduce函数接收到的value list是按照value排序的.这种应用需求在 ...
- java学习——异常处理
类 Throwable类 Java 语言中所有错误或异常的超类.只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw语句抛出.类似地,只有此类 ...
- 年底Android面试整理(附答案)
面试,无非都是问上面这些问题(挺多的 - -!),聘请中高级的安卓开发会往深的去问,并且会问一延伸二.以下我先提出几点重点,是面试官基本必问的问题,请一定要去了解! 基础知识 – 四大组件(生命周期, ...
- 谷歌被爆秘密研发新系统 欲5年内取代Android
谷歌2年多来有一群工程师秘密研发新系统,希望最终能取代手机操作系统安卓.安卓日前遭欧盟以反垄断为由重罚. 谷歌的新研发计划Fuchsia是从零开始,希望在更多个人装置和各式小巧装置联机上网的情况下,能 ...
- ionic3 使用html2canvas将数据导出为图片,并下载本地
1.安装html2canvas npm install --save html2canvas 官方网站 https://html2canvas.hertzen.com/ 2.在需要的组件中引入html ...
- CentOS 7 部署 Spring Boot
Spring Boot 内嵌了tomcat .我们可以将Boot打成 jar 包丢到服务器上运行才行. Spring Boot已经帮我们打理好了这一切,如果项目是继承自 spring-boot-sta ...
- IntersectionObserver API 使用教程
转载:原文地址:http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html 网页开发时,常常需要了解某个元素是否进入了&q ...