ARC090E Avoiding Collision 题解

Description

给定一个 n n n 个点, m m m 条边的无向图,两个人分别从 S S S 走到 T T T T T T 走到 S S S

每条边需要花费一定的时间通过。

两个人走的路径耗时都是最短的,且两人不会相遇(即在同一时刻两人不在同一点或同一边)。

问有多少种方案满足上述要求。

两种方案不同当且仅当有至少一人走的路径不同。

Solution

首先考虑正向得出答案。

我们发现一条边 ( u , v ) (u,v) (u,v) 若能是 S S S T T T 的最短路的一部分,那么 d i s ( S , u ) dis(S,u) dis(S,u) d i s ( v , T ) dis(v,T) dis(v,T) 一定确定,即使是在两条不一样的最短路上。

那么为了不相遇,两人走的路径包含的边集一定不交。

然后就会顺畅的想到每条边松弛后只更新一条边,保证最后得出的每一条最短路的边集的交集为空。

然而稍微细想就会发现这是无法保证的,同时也不是正确答案。

因为:

  1. 无法保证松弛后更新的唯一边在最短路中。
  2. 可能 a , b a,b a,b 两条最短路径有交但 ( a , c ) , ( c , a ) , ( b , c ) , ( c , b ) (a,c),(c,a),(b,c),(c,b) (a,c),(c,a),(b,c),(c,b) 是合法方案。
  3. 两条最短路径可能只在一个点相交,而不是边。

说了那么多,就是为了让你死了正向推这条心(也有可能作者太菜想不出来) 发现容斥是可行的。

Realsol

发现两个人最多只会相遇一次(注意两条最短路径可能有多个部分重叠)。

分类讨论相遇是在点或边。

M d i s Mdis Mdis 为最短路, d i s s 0 , x , c n t t 0 , x , d i s s 1 , x , c n t t 1 , x diss_{0,x},cntt_{0,x},diss_{1,x},cntt_{1,x} diss0,x,cntt0,x,diss1,x,cntt1,x 分别为 S S S x x x 的最短耗时、最短路个数, T T T x x x 的最短耗时、最短路个数, d i s ( x , y ) dis(x,y) dis(x,y) 代表无向边 ( x , y ) (x,y) (x,y) 的耗时。

若相遇在点 x x x,则满足 d i s s 0 , x = d i s s 1 , x diss_{0,x}=diss_{1,x} diss0,x=diss1,x,同时满足 d i s s 0 , x + d i s s 1 , x = M d i s diss_{0,x}+diss_{1,x}=Mdis diss0,x+diss1,x=Mdis 的最短耗时要求,此方案个数为 ( c n t t 0 , x × c n t t 1 , x ) 2 (cntt_{0,x}\times cntt_{1,x})^2 (cntt0,x×cntt1,x)2

若相遇在边 ( x , y ) (x,y) (x,y),则满足 d i s s 0 , x + d i s ( x , y ) > d i s s 1 , y , d i s s 1 , y + d i s ( x , y ) > d i s s 0 , x diss_{0,x}+dis(x,y)>diss_{1,y},diss_{1,y}+dis(x,y)>diss_{0,x} diss0,x+dis(x,y)>diss1,y,diss1,y+dis(x,y)>diss0,x,同时满足 d i s s 0 , x + d i s ( x , y ) + d i s s 1 , y = M d i s diss_{0,x}+dis(x,y)+diss_{1,y}=Mdis diss0,x+dis(x,y)+diss1,y=Mdis 的最短耗时要求,此方案个数为 ( c n t t 0 , x × c n t t 1 , y ) 2 (cntt_{0,x}\times cntt_{1,y})^2 (cntt0,x×cntt1,y)2

注意此为 S → x → y → T S\rightarrow x\rightarrow y\rightarrow T SxyT 的情况,由于 ( x , y ) (x,y) (x,y) 是无向边,所以还要考虑 S → y → x → T S\rightarrow y\rightarrow x\rightarrow T SyxT 的情况。

最后用总方案数 c n t t 0 , T × c n t t 1 , S cntt_{0,T}\times cntt_{1,S} cntt0,T×cntt1,S 减去上面不满足要求的方案即可得出正确答案。

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mo=1000000007;
priority_queue<pair<ll,int> >q; 
int n,m,s,t;
int tot,head[100010];
int u[200020],v[200020];
ll diss[2][100010],dis[100010],d[200020];
ll cntt[2][100010],cnt[100010];
bool vis[100010];
struct edge{
	int to,next;
	ll w;
}e[400040];
void add(int x,int y,ll z){
	e[++tot]=edge{y,head[x],z};
	head[x]=tot;
}
void dijsktra(ll *dis,ll *cnt,int st){
	for(int i=1;i<=n;i++){
		dis[i]=1e15;
		vis[i]=0;
	}
	dis[st]=0,cnt[st]=1;
	q.push({0,st});
	while(q.size()){
		int x=q.top().second;
		q.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=head[x];i;i=e[i].next){
			int y=e[i].to;
			ll w=e[i].w;
			if(dis[y]<dis[x]+w) continue;
			else if(dis[y]==dis[x]+w){
				cnt[y]+=cnt[x];
				cnt[y]%=mo;
				continue;
			}
			cnt[y]=cnt[x];
			dis[y]=dis[x]+w;
			if(vis[y]) continue;
			q.push({-dis[y],y});
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(nullptr);
	cin>>n>>m>>s>>t;
	for(int i=1;i<=m;i++){
		int x,y;
		ll z;
		cin>>x>>y>>z;
		add(x,y,z),add(y,x,z);
		u[i]=x,v[i]=y,d[i]=z;
	}
	dijsktra(diss[0],cntt[0],s);
	dijsktra(diss[1],cntt[1],t);
	ll ans=cntt[0][t]*cntt[0][t]%mo;
	for(int i=1;i<=n;i++){
		if(diss[0][i]==diss[1][i]&&diss[0][i]+diss[1][i]==diss[0][t]){
			ans=(ans+mo-cntt[0][i]*cntt[1][i]%mo*cntt[0][i]%mo*cntt[1][i]%mo)%mo;
		}
	}
	for(int i=1;i<=m;i++){
		if(diss[0][u[i]]+d[i]>diss[1][v[i]]&&diss[1][v[i]]+d[i]>diss[0][u[i]]&&diss[0][u[i]]+d[i]+diss[1][v[i]]==diss[0][t]){
			ans=(ans+mo-cntt[0][u[i]]*cntt[1][v[i]]%mo*cntt[0][u[i]]%mo*cntt[1][v[i]]%mo)%mo;
		}
		swap(u[i],v[i]);
		if(diss[0][u[i]]+d[i]>diss[1][v[i]]&&diss[1][v[i]]+d[i]>diss[0][u[i]]&&diss[0][u[i]]+d[i]+diss[1][v[i]]==diss[0][t]){
			ans=(ans+mo-cntt[0][u[i]]*cntt[1][v[i]]%mo*cntt[0][u[i]]%mo*cntt[1][v[i]]%mo)%mo;
		}
	}
	cout<<ans;
	return 0;
}
负迁移是指在学习新知识或技能时,旧知识或技能对新学习的干扰或阻碍。为了描述和避免负迁移,我们需要理解以下几个方面。 首先,负迁移的特征之一是旧知识或技能与新学习之间的相似性。如果两者在概念、原则或策略上相似,但其应用方式不同,负迁移可能发生。例如,如果一个人之前学习过一种语言,然后学习另一种语言时,相似的语法规则可能导致负迁移。因此,我们需要注意并识别旧知识与新学习之间的相似性。 其次,学习顺序也会影响负迁移的发生。如果我们先学习一种方法,然后学习另一种与之相冲突的方法,那么负迁移可能会发生。例如,在学习不同的乐器时,可能会发生负迁移,因为每种乐器的演奏技巧和指法都不同。因此,我们需要合理安排学习顺序,避免相互冲突的知识或技能之间的学习。 最后,为了避免负迁移,我们可以采取一些策略。首先,我们应该引导学习者通过比较和对比来识别旧知识和新学习之间的相似性和差异性。其次,我们可以通过提供明确的指导、重视练习和巩固,以及提供针对旧知识或技能的修正措施来帮助学习者克服负迁移。此外,我们也可以鼓励学习者主动思考和运用前一知识对新学习的影响,以更好地理解和纠正可能存在的负迁移。 总之,了解负迁移的特征,并采取相应的避免策略,可以帮助我们更好地应对负迁移现象,促进有效的学习和知识传递。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值