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

  这道题目的突破口在于正难则反。直接求有多少不相交的不好求,我们转而求出所有相交的。我们先预处理出由 \(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. Ruby & Rails学习资料

    ------------------教程------------- Ruby风格指南(代码规范) https://github.com/bbatsov/ruby-style-guide 笨方法學 Ru ...

  2. 苏醒的巨人----CSRF

    一.CSRF 跨站请求伪造(Cross-Site Request Forgery,CSRF)是指利用 受害者尚未失效的身份认证信息(cookie.会话等),诱骗其点 击恶意链接或者访问包含攻击代码的页 ...

  3. 【SpringCloud】第四篇:断路器(Hystrix)

    前言: 必需学会SpringBoot基础知识 简介: spring cloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选. ...

  4. Python-S9——Day82-CRM项目实战

    1.权限的概念: 2.RBAC的设计: 3.注册登录用户所有权限到session中: 4.权限的校验: 5.基于中间件的权限校验: 1.权限的概念: 1.1 项目与应用: Project App 1. ...

  5. C++11 type_traits 之is_pointer,is_member_function_pointer源码分析

    源码如下: template<typename> struct __is_pointer_helper : public false_type { }; template<typen ...

  6. * 197. Permutation Index【LintCode by java】

    Description Given a permutation which contains no repeated number, find its index in all the permuta ...

  7. leetcode个人题解——two sum

    这是leetcode第一题,通过较为简单. 第一题用来测试的,用的c,直接暴力法过, /** * Note: The returned array must be malloced, assume c ...

  8. Cortex-M3(NXP LPC 1788) 启动代码

    startup_LPC177x_8x.s启动代码分析. 参考资料: Cortex-M3 (NXP LPC1788)之启动代码分析 ARM启动过程(Cortex-M3 NXP LPC1768为例) ;/ ...

  9. PCB各层介绍及AD软件画PCB时的规则

    好久没画过板了,最近因为工作关系,硬件软件全部得自己来,不得不重新打开闲置很久的AltiumDesigner.以前做过点乱七八糟的笔记,本来想回头翻看一下,结果哪儿也找不到,估计已经被不小心删掉了.  ...

  10. 最小生成树(Kruskal和Prim算法)

    关于图的几个概念定义:          关于图的几个概念定义: 连通图:在无向图中,若任意两个顶点vi与vj都有路径相通,则称该无向图为连通图. 强连通图:在有向图中,若任意两个顶点vi与vj都有路 ...