题目传送门:ARC090E

题意简述:

给定一张有 \(N\) 个点 \(M\) 条边的无向图。每条边有相应的边权,边权是正整数。

小 A 要从结点 \(S\) 走到结点 \(T\) ,而小 B 则相反,他要从结点 \(T\) 走到结点 \(S\) 。

小 A 和小 B 走一条边需要的时间都是这条边的边权,不论方向。

问有多少种走法,使得他们俩都走了最短路,但是他们不会相遇,这里相遇指的是在点上或者在边上相遇。

答案对 \(10^9+7\) 取模。

题解:

用 Dijkstra 算法求出以结点 \(S\) 和结点 \(T\) 出发到每个点的最短路和最短路条数。

把从结点 \(S\) 到结点 \(i\) 的最短路记作 \(d1_i\) ,最短路条数对 \(10^9+7\) 取模的结果记作 \(g1_i\)。

把从结点 \(T\) 到结点 \(i\) 的最短路记作 \(d2_i\) ,最短路条数对 \(10^9+7\) 取模的结果记作 \(g2_i\)。

把从结点 \(S\) 到结点 \(T\) 的最短路记作 \(Dist\) 。

考虑用容斥的方法计算答案。答案等于总方案数减去相遇的方案数。总方案数为 \(g1_T^2\) 。

因为走的都是最短路,而且边权是正的,不难证明两人只会相遇一次。

所以只要统计在每个点或者每条边经过的方案数即可。

考虑经过结点 \(i\) 的方案数:
前提是 \(d1_i+d2_i=Dist\) 且 \(d1_i=d2_i\) ,方案数为 \(g1_i^2g2_i^2\) 。

考虑经过边 \(i\overset{d}{\Longleftrightarrow}j\) (其中小 A 从结点 \(i\) 走向结点 \(j\) )的方案数:
前提是 \(d1_i+d+d2_i=Dist\) 且 \(d1_i+d>d2_j\) 且 \(d1_i<d+d2_j\) ,方案数为 \(g1_i^2g2_j^2\) 。

 #include<bits/stdc++.h>
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define eF(i,u) for(int i=h[u];i;i=nxt[i])
#define Mod 1000000007
using namespace std;
typedef long long ll;
typedef pair<ll,int> pli; int n,m,S,T;
ll Ans;
int U[],V[],D[];
int h[],nxt[],to[],w[],tot;
void ins(int x,int y,int z){nxt[++tot]=h[x];to[tot]=y;w[tot]=z;h[x]=tot;} ll d1[],d2[],g1[],g2[];bool v1[],v2[];
priority_queue<pli,vector<pli>,greater<pli> > pq; void Dij(ll*d,ll*g,bool*v,int s){
d[s]=0ll;
pq.push(pli(0ll,s));
g[s]=;
while(!pq.empty()){
pli P=pq.top(); pq.pop();
int u=P.second; ll du=P.first;
if(v[u]||d[u]<du) continue;
v[u]=;
eF(i,u){
if(d[to[i]]==du+w[i])
g[to[i]]=(g[to[i]]+g[u])%Mod;
if(d[to[i]]>du+w[i])
g[to[i]]=g[u],
d[to[i]]=du+w[i], pq.push(pli(d[to[i]],to[i]));
}
}
} int main(){
int x,y,z;
scanf("%d%d",&n,&m);
scanf("%d%d",&S,&T);
F(i,,m) scanf("%d%d%d",&x,&y,&z), ins(x,y,z), ins(y,x,z), U[i]=x, V[i]=y, D[i]=z;
memset(d1,0x3f,sizeof d1);
Dij(d1,g1,v1,S);
memset(d2,0x3f,sizeof d2);
Dij(d2,g2,v2,T);
ll Dist=d1[T];
Ans=g1[T]*g1[T]%Mod;
F(i,,n){
if(d1[i]+d2[i]==Dist&&d1[i]==d2[i])
Ans=(Ans-g1[i]*g1[i]%Mod*g2[i]%Mod*g2[i]%Mod)%Mod;
}
int u,v,d;
F(i,,m){
u=U[i], v=V[i], d=D[i];
if(d1[u]+d+d2[v]==Dist && d1[u]+d>d2[v] && d2[v]+d>d1[u]){
Ans=(Ans-g1[u]*g2[v]%Mod*g1[u]%Mod*g2[v]%Mod)%Mod;
}
u=V[i], v=U[i], d=D[i];
if(d1[u]+d+d2[v]==Dist && d1[u]+d>d2[v] && d2[v]+d>d1[u]){
Ans=(Ans-g1[u]*g2[v]%Mod*g1[u]%Mod*g2[v]%Mod)%Mod;
}
}
printf("%lld",(Ans%Mod+Mod)%Mod);
return ;
}

AtCoder ARC 090 E / AtCoder 3883: Avoiding Collision的更多相关文章

  1. [AtCoder arc090E]Avoiding Collision

    Description 题库链接 给出一张 \(N\) 个节点, \(M\) 条边的无向图,给出起点 \(S\) 和终点 \(T\) .询问两个人分别从 \(S\) 和 \(T\) 出发,走最短路不相 ...

  2. 【题解】Atcoder ARC#90 E-Avoiding Collision

    自己做出来固然开心,但是越发感觉到自己写题的确是很慢很慢了……往往有很多的细节反反复复的考虑才能确定,还要加油呀~ 这道题目的突破口在于正难则反.直接求有多少不相交的不好求,我们转而求出所有相交的.我 ...

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

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

  4. AtCoder ARC 076E - Connected?

    传送门:http://arc076.contest.atcoder.jp/tasks/arc076_c 平面上有一个R×C的网格,格点上可能写有数字1~N,每个数字出现两次.现在用一条曲线将一对相同的 ...

  5. AtCoder ARC 076D - Built?

    传送门:http://arc076.contest.atcoder.jp/tasks/arc076_b 本题是一个图论问题——Manhattan距离最小生成树(MST). 在一个平面网格上有n个格点, ...

  6. AtCoder ARC 082E - ConvexScore

    传送门:http://arc082.contest.atcoder.jp/tasks/arc082_c 本题是一个平面几何问题. 在平面直角坐标系中有一个n元点集U={Ai(xi,yi)|1≤i≤n} ...

  7. Atcoder ARC 082C/D

    C - Together 传送门:http://arc082.contest.atcoder.jp/tasks/arc082_a 本题是一个数学问题. 有一个长度为n的自然数列a[1..n],对于每一 ...

  8. 【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)

    题面 题目大意: 给你\(m\)张椅子,排成一行,告诉你\(n\)个人,每个人可以坐的座位为\([1,l]\bigcup[r,m]\),为了让所有人坐下,问至少还要加多少张椅子. Solution: ...

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

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

随机推荐

  1. js 添加事件兼容性

    var tools = { //添加事件 addHandle: function (e, type, handle) { if (e.addEventListener) { e.addEventLis ...

  2. UVAlive4255_Guess

    题目很好很有意思. 告诉你n个序列中,任意一个连续子序列的和与0相比较的结果. 构造一个满足条件的序列. 对于从x->y这一段的和,如果大于0,那么sum[x]>sum[y-1],显然我们 ...

  3. MT【116】三个点动起来

    评:当若干个变量时抓住主变量,立体几何问题平面化.

  4. UIScrollView浏览一组图片,且图片与图片之间有间隔

    ---恢复内容开始--- UIScrollView是可以浏览一组view的,只要将其属性 pagingEnabled设置为true就可以了.具体过程是这样的, 1:将一组图片按照从左到右的顺序添加到U ...

  5. Palindrome Number - LeetCode

    目录 题目链接 注意点 解法 小结 题目链接 Palindrome Number - LeetCode 注意点 负数肯定是要return false的 数字的位数要分奇数和偶数两种情况 解法 解法一: ...

  6. Android Studio导入ApiDemos

    安卓开发入门篇(一):Android Studio导入ApiDemoshttp://blog.csdn.net/dreamer2020/article/details/52316895 https:/ ...

  7. LGP4518[JSOI2018]绝地反击

    题解: 只要确定了每艘飞船的就位位置,就可以用二分+网络流求得答案: 定义偏转角度$a$为离$x$正半轴逆时针最近的边的弧度,$a \in [0,\frac{2\pi}{n})$ 二分一个值,对于一个 ...

  8. python之旅:函数基础

    一.引子 1.函数是什么 用函数与不用函数 #1.代码的组织结构不清晰,可读性差 #2.遇到重复的功能只能重复编写实现代码,代码冗余 #3.功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一 ...

  9. easyUI datetimebox 自定义显示格式

    http://blog.csdn.net/littlewolf766/article/details/7329123 项目里需要显示自定义显示格式,比如只显示yyy,yyyy-mm,yyyy-mm-d ...

  10. C#线程篇---线程池如何管理线程(6完结篇)

    C#线程基础在前几篇博文中都介绍了,现在最后来挖掘一下线程池的管理机制,也算为这个线程基础做个完结. 我们现在都知道了,线程池线程分为工作者线程和I/O线程,他们是怎么管理的? 对于Microsoft ...