相遇(容斥+最短路+分类,水紫)
给定一个有n个节点m条边的无向图,在某一时刻节点st上有一个动点a, 节点end上有一个动点b, 动点a向节点end方向移动,要求是尽快到达end点,与此同时,动点b向节点st方向移动,要求是尽快到达st点, 但是整个过程中a和b不能相遇,问两点不相遇一共有多少种方案。
不相遇是指在同一时刻两点都不在同一节点或同一边上。结果可能很大,对1e9+7取模
输入格式
第一行两个整数n和m
第二行两个整数st和end
接下来m行,每行三个整数u,v,t, 表示u和v有一条长为t的边
其中1<=n<=1e5, 1<=m<=2e5,1<=t<=1e9
数据不存在重边和自环
输出格式
一个整数
输入/输出例子1
输入:
4 4
1 3
1 2 1
2 3 1
3 4 1
4 1 1
输出:
2
样例解释
无
直接求不相遇比较难,用减法原理。
很容易想到,首先要搞一个最短路计数。
dis[i]:s->i最短路,cnt[i]:s->i的最短路路径数
dis2[i]:t->i最短路,cnt2[i]:t->i的最短路路径数
用全部方案-相遇方案,就是答案
全部方案:最短路径条数平方。也就是 cnt[t]*cnt[t](cnt2[s]*cnt2[s] 也行)
相遇是在节点上相遇或者边上相遇
分别算就好
判断能否在u节点相遇:
枚举每个点,看看能否在点上相遇
条件:看看dis[s->u]是否等于dis[t->u],且s-u + t-u 是最短路
贡献:(cnt[u]*cnt2[u])^2
计算如下:
假设s到u有3条路可以走,t到u也有3条路可以走
那么我们可以考虑让s走第1条,走到t可以分别走3条。
我们还可以考虑让s走第2条,走到t可以分别走3条。
我们还可以考虑让s走第3条,走到t可以分别走3条。
所以就是 cnt[u]*cnt2[u]
但是我们还可以反过来,从t走,走到s
那么我们可以考虑让t走第1条,走到s可以分别走3条。
我们还可以考虑让t走第2条,走到s可以分别走3条。
我们还可以考虑让t走第3条,走到s可以分别走3条。
所以就是 cnt[u]*cnt2[u]
那么答案就是这俩相乘。
边上相遇:
枚举每条边,是否会在那条边相遇。
条件:这条边在最短路上。 s-u+w+t-v 是最短路
还有两个条件:
dis[s->u]+w>dis[t->v]
dis[s->v]+w>dis[t->u]
这里第二个条件类似第一个条件,就是u,v换了下而已。
举个例看看:
比如:u->v,也就是 w=3,v->t=6,也就是dis[v->t]=6
如果dis[s->u]是3,就或在6这个地方相遇,也就是v号点。(也就是说dis[s->u]+w = dis[v-t]是不行的)
那如果此时调整一下dis[s->u],我们减小一下,改成dis[s->u]是2,会在5.5这个地方相遇,那么这个时候会超过v (也就是说dis[s->u]+w<dis[v-t]是不行的)
再改,dis[s->u]是4,会在6.5这个地方相遇,刚好在v里面。(也就是说 dis[s->u]+w>dis[v-t]是可行的)
也就是说,一个人走过这条边之前,另一个人必须至少走上这条边。
贡献:(cnt[s-u]*cnt[t-v])^2
和计算点的贡献是一样的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | #include <bits/stdc++.h> #define int long long using namespace std; const int N=200005, Mod=1e9+7; struct node { int v, w; bool operator <( const node &A) const { return w>A.w; }; }; struct node2 { int u, v, w; }ask[N]; int n, m, s, t, u1, v1, w1; int dis[N], vis[N], cnt[N], dis2[N], vis2[N], cnt2[N], ans=0, sum=0; vector<node> a[N]; priority_queue<node> q, q2; void dij() { memset (dis, 63, sizeof dis); memset (vis, 0, sizeof vis); dis[s]=0, cnt[s]=1; q.push({s, 0}); while (!q.empty()) { int u=q.top().v; q.pop(); if (vis[u]) continue ; vis[u]=1; for ( int i=0; i<a[u].size(); i++) { int v=a[u][i].v, w=a[u][i].w; if (dis[v]>dis[u]+w) { dis[v]=dis[u]+w; q.push({v, dis[v]}); cnt[v]=cnt[u]%Mod; } else if (dis[v]==dis[u]+w) cnt[v]=(cnt[v]+cnt[u])%Mod; } } } void dij2() { memset (dis2, 63, sizeof dis2); memset (vis2, 0, sizeof vis2); dis2[t]=0, cnt2[t]=1; q2.push({t, 0}); while (!q2.empty()) { int u=q2.top().v; q2.pop(); if (vis2[u]) continue ; vis2[u]=1; for ( int i=0; i<a[u].size(); i++) { int v=a[u][i].v, w=a[u][i].w; if (dis2[v]>dis2[u]+w) { dis2[v]=dis2[u]+w; q2.push({v, dis2[v]}); cnt2[v]=cnt2[u]%Mod; } else if (dis2[v]==dis2[u]+w) cnt2[v]=(cnt2[v]+cnt2[u])%Mod; } } } signed main() { scanf ( "%d%d%d%d" , &n, &m, &s, &t); for ( int i=1; i<=m; i++) { scanf ( "%d%d%lld" , &u1, &v1, &w1); a[u1].push_back({v1, w1}); a[v1].push_back({u1, w1}); ask[i]={u1, v1, w1}; } dij(); dij2(); sum=dis[t]; ans=cnt[t]*cnt[t]; for ( int i=1; i<=n; i++) if (dis[i]==dis2[i] && dis[i]+dis2[i]==sum) ans=((ans-(cnt[i]*cnt[i]%Mod*cnt2[i]%Mod*cnt2[i]%Mod))+Mod)%Mod; //printf("%lld\n", ans%Mod); for ( int i=1; i<=m; i++) { int u=ask[i].u, v=ask[i].v, w=ask[i].w; if (dis[u]+w+dis2[v]==sum && dis[u]+w>dis2[v] && dis2[v]+w>dis[u]) ans=((ans-cnt[u]*cnt[u]%Mod*cnt2[v]%Mod*cnt2[v]%Mod)+Mod)%Mod; swap(u, v); if (dis[u]+w+dis2[v]==sum && dis[u]+w>dis2[v] && dis2[v]+w>dis[u]) ans=((ans-cnt[u]*cnt[u]%Mod*cnt2[v]%Mod*cnt2[v]%Mod)+Mod)%Mod; } printf ( "%lld" , ans%Mod); return 0; } |
__EOF__

本文链接:https://www.cnblogs.com/didiao233/p/18378318.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话