自己做出来固然开心,但是越发感觉到自己写题的确是很慢很慢了……往往有很多的细节反反复复的考虑才能确定,还要加油呀~

  这道题目的突破口在于正难则反。直接求有多少不相交的不好求,我们转而求出所有相交的。我们先预处理出由 \(S\) 到 \(T\) 的最短路图(跑一边Dijkstra,所有的最短路径构成的图),显然可以顺便处理出 \(T\) 到 \(S\) 的。然后这个图是一个拓扑图,满足的性质就是从 \(S\) 点出发的任意一条路径终点均为 \(T\) 且为二者之间的最短路。拓扑图dp对于每个点我们又可以获得  \(Way1[u],  Way2[u]\) 分别表示从起点到 \(u\) 点的总路径数和从终点到 \(u\) 的总路径数。

  之后我们可以分类讨论一下,两条路径相遇是相遇在点上还是相遇在边上。相遇在点上很好判断,就是从起点到 \(u\) 点的距离正好等于从 \(u\) 点到终点的距离;相遇在边上则要求路径的终点落在这条边上,也是可以 O(1) 判断的。这样就好啦~(๑´ㅂ`๑)

#include <bits/stdc++.h>
using namespace std;
#define maxn 500000
#define mod 1000000007
#define int long long
int n, m, dis1[maxn], dis2[maxn];
int ans, K, S, T, Way1[maxn], Way2[maxn];
bool vis[maxn]; int read()
{
int x = , k = ;
char c; c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct edge
{
int cnp, fr[maxn], to[maxn], co[maxn];
int last[maxn], head[maxn], degree[maxn];
edge() { cnp = ; }
void add(int u, int v, int w = )
{
fr[cnp] = u, to[cnp] = v, co[cnp] = w;
last[cnp] = head[u], head[u] = cnp ++;
}
}E[], G; struct node
{
int x, y;
node(int _x = , int _y = ) { x = _x, y = _y; }
friend bool operator <(const node& a, const node& b)
{ return a.y > b.y; }
}; priority_queue <node> q; void Up(int &x, int y) { x = (x + y) % mod; }
int Qpow(int x) { return x * x % mod; }
void Dijk(int S, int *dis)
{
memset(vis, , sizeof(vis));
dis[S] = ; q.push(node(S, ));
while(!q.empty())
{
node now = q.top(); q.pop();
int u = now.x; if(vis[u]) continue; vis[u] = ;
for(int i = G.head[u]; i; i = G.last[i])
{
int v = G.to[i];
if(dis[v] > dis[u] + G.co[i])
{
dis[v] = dis[u] + G.co[i];
q.push(node(v, dis[v]));
}
}
}
} void Toposort()
{
memset(vis, , sizeof(vis));
queue <int> q; q.push(S);
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = G.head[u]; i; i = G.last[i])
{
int v = G.to[i];
if((dis1[u] + dis2[v] + G.co[i]) == K)
{
E[].add(u, v); E[].degree[v] ++;
E[].add(v, u); E[].degree[u] ++;
if(!vis[v]) q.push(v), vis[v] = ;
}
}
}
} void TopoDP(int opt, int *Way)
{
queue <int> q;
for(int i = ; i <= n; i ++)
if(!E[opt].degree[i])
q.push(i), Way[i] = ;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = E[opt].head[u]; i; i = E[opt].last[i])
{
int v = E[opt].to[i];
E[opt].degree[v] --; Up(Way[v], Way[u]);
if(!E[opt].degree[v]) q.push(v);
}
}
} signed main()
{
n = read(), m = read(); S = read(), T = read();
for(int i = ; i <= m; i ++)
{
int x = read(), y = read(), w = read();
G.add(x, y, w), G.add(y, x, w);
}
memset(dis1, , sizeof(dis1)); memset(dis2, , sizeof(dis2));
Dijk(S, dis1), Dijk(T, dis2);
K = dis1[T]; Toposort();
TopoDP(, Way1); TopoDP(, Way2);
for(int i = ; i <= n; i ++)
if(dis1[i] + dis1[i] == K)
Up(ans, Qpow(Way1[i] * Way2[i] % mod) % mod);
for(int i = ; i < E[].cnp; i ++)
{
int u = E[].fr[i], v = E[].to[i];
if(dis1[u] * == K || dis1[v] * == K) continue;
if(K > * dis1[u] && K < * (K - dis2[v]))
Up(ans, Qpow(Way1[u] * Way2[v] % mod) % mod);
}
ans = (Way1[T] * Way1[T] % mod - ans + mod) % mod;
printf("%lld\n", ans);
return ;
}

【题解】Atcoder ARC#90 E-Avoiding Collision的更多相关文章

  1. 【题解】Atcoder ARC#90 F-Number of Digits

    Atcoder刷不动的每日一题... 首先注意到一个事实:随着 \(l, r\) 的增大,\(f(r) - f(l)\) 会越来越小.考虑暴力处理出小数据的情况,我们可以发现对于左端点 \(f(l) ...

  2. [题解] Atcoder ARC 142 D Deterministic Placing 结论,DP

    题目 (可能有点长,但是请耐心看完,个人认为比官方题解好懂:P) 首先需要注意,对于任意节点i上的一个棋子,如果在一种走法中它走到了节点j,另一种走法中它走到了节点k,那么这两种走法进行完后,棋子占据 ...

  3. [题解] Atcoder ARC 142 E Pairing Wizards 最小割

    题目 建图很妙,不会. 考虑每一对要求合法的巫师(x,y),他们两个的\(a\)必须都大于\(min(b_x,b_y)\).所以在输入的时候,如果\(a_x\)或者\(a_y\)小于\(min(b_x ...

  4. AtCoder ARC 090 E / AtCoder 3883: Avoiding Collision

    题目传送门:ARC090E. 题意简述: 给定一张有 \(N\) 个点 \(M\) 条边的无向图.每条边有相应的边权,边权是正整数. 小 A 要从结点 \(S\) 走到结点 \(T\) ,而小 B 则 ...

  5. [题解] Atcoder Regular Contest ARC 147 A B C D E 题解

    点我看题 A - Max Mod Min 非常诈骗.一开始以为要观察什么神奇的性质,后来发现直接模拟就行了.可以证明总操作次数是\(O(nlog a_i)\)的.具体就是,每次操作都会有一个数a被b取 ...

  6. 【题解】Atcoder ARC#96 F-Sweet Alchemy

    首先,我们发现每一个节点所选择的次数不好直接算,因为要求一个节点被选择的次数大于等于父亲被选择的次数,且又要小于等于父亲被选择的次数 \(+D\).既然如此,考虑一棵差分的树,规定每一个节点被选择的次 ...

  7. 【题解】Atcoder ARC#94 F-Normalization

    再次膜拜此强题!神级性质之不可能发现系列收藏++:首先,对于长度<=3的情况,我们采取爆搜答案(代码当中是打表).对于长度>=4的情况,则有如下几条玄妙的性质: 首先我们将 a, b, c ...

  8. [题解] Atcoder Regular Contest ARC 148 A B C E 题解

    点我看题 题目质量一言难尽(至少对我来说 所以我不写D的题解了 A - mod M 发现如果把M选成2,就可以把答案压到至多2.所以答案只能是1或2,只要判断答案能不能是1即可.如果答案是1,那么M必 ...

  9. [题解] Atcoder Regular Contest ARC 151 A B C D E 题解

    点我看题 昨天刚打的ARC,题目质量还是不错的. A - Equal Hamming Distances 对于一个位置i,如果\(S_i=T_i\),那么不管\(U\)的这个位置填什么,对到\(S\) ...

随机推荐

  1. 1030: [JSOI2007]文本生成器

    1030: [JSOI2007]文本生成器 https://www.lydsy.com/JudgeOnline/problem.php?id=1030 分析: AC自动机+dp. 正难则反,求满足的, ...

  2. Sql Server Profiler使用

            在使用Entity Framework的过程当中,有时候需要看Entity Framework自动生成的Sql语句,在客户端可以使用跟踪的方法看到每次查询时的Sql语句,其实通过数据库 ...

  3. pip源设置 & pandas安装

    pip的官方源python.pypi.org貌似被墙,换用国内安装源 网上的设置方法都是基于Unix的,Windows下的设置略麻烦. 更新..\Lib\site-packages\pip下的cmdo ...

  4. create-react-app创建react项目 css模块化处理

    用的css预处理器用sass,其他大同小异. 用create-react-app创建项目,执行npm run eject弹出配置文件(此操作不可逆): 配置sass,用的最新的CRA,webpack4 ...

  5. Qt-Qml-播放视频-失败版-只有声音没有图像

    失败版代码 import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 import QtMultimedia ...

  6. 《Spark 官方文档》在Mesos上运行Spark

    本文转自:http://ifeve.com/spark-mesos-spark/ 在Mesos上运行Spark Spark可以在由Apache Mesos 管理的硬件集群中运行. 在Mesos集群中使 ...

  7. Ubuntu16.04安装wps办公软件解决文字缺失

    先到wps官网下载linux版wps安装包 选择64位的alpha版本下载: 下载完后,同样是cd到Downloads目录,用dpkg命令来安装它: cd  Downloads/ sudo dpkg ...

  8. CDH/Hadoop 5.15 installation steps

    I will talk the main steps to install CDH 5.15 on Linux(CENT OS 6.10).  The installation method is M ...

  9. kaldi HMM-GMM全部训练脚本分解

    目录 train_mono.sh train_deltas.sh train_lda_mllt.sh train_sat.sh train_mono.sh 单音素训练脚本: //初始化,[topo f ...

  10. SpringBoot项目打包成jar后,启动脚本

    将springboot项目打包成jar后,上传至服务器,每次都需要手敲命令,重新部署项目,可将这些命令写入脚本中,直接运行. 启动脚本(start.sh): CUR_PATH=$(cd "$ ...