2018.11.05【校内模拟】规避(最短路计数)(容斥)(正难则反)

传送门


解析:

首先直接统计并不好做,考虑反着做,先求出总共的方案数,然后减去相遇的方案数。

总方案数就是SSTT的最短路数量的平方(两人分别作选择)。

首先这是个计数类问题,先做一个最短路计数。

distSudistS_u表示SSuu的最短路长度,cntSucntS_u表示SSuu的最短路数量,distTudistT_ucntTucntT_u同理,记S,TS,T最短路长度为tottot

怎么统计相遇?
首先我们发现两人的相交位置一定是最短路的中点,这个中点可能是点也可能是边,所以考虑以中点为标志统计答案。

当一个点不在任何一条最短路上时,直接passpass
否则若这个点uu满足distSu==distTudistS_u==distT_u,则两人有可能在这个点上相遇,方案数为(cntSu×cntTu)2(cntS_u\times cntT_u)^2,因为两人要走完全程,又必须经过点uu,根据乘法原理可以轻易得出答案。

如果这个点uu满足,存在一条边e=<u,v>e=<u,v>
distSv==distSu+wedistS_v==distS_u+w_e(即它存在于最短路上),distSutot/2distS_u\le tot/2distTvtot/2distT_v\le tot/2

那么两人就可能在这条边上相遇。那么经过这条边的最短路数就是cntSu×cntTvcntS_u\times cntT_v,根据乘法原理,平方一下就好了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

cs ll mod=1000000007;
cs int N=100005,M=200005;
int last[N],nxt[M<<1],to[M<<1],ecnt;
int w[M<<1];
inline void addedge(int u,int v,int val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
}

ll distS[N],distT[N];
ll cntS[N],cntT[N],tot,ans;
bool flag;
bool vis[N];
set<pair<ll,int> > q;
inline void Dijkstra(ll *cs dist,ll *cs cnt,int S,int T){
	memset(dist,0x3f,sizeof distS);
	dist[S]=0;cnt[S]=1;
	q.clear();
	q.insert(make_pair(0,S));
	memset(vis,0,sizeof vis);
	while(!q.empty()){
		int u=q.begin()->second;
		q.erase(q.begin());
		if(vis[u])continue;
		vis[u]=true;
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
			if(dist[v]>dist[u]+w[e]){
				q.erase(make_pair(dist[v],v));
				dist[v]=dist[u]+w[e];
				cnt[v]=0;
				q.insert(make_pair(dist[v],v));
			}
			if(dist[v]==dist[u]+w[e])cnt[v]=(cnt[v]+cnt[u])%mod;
		}
	}
} 

int S,T;
int n,m;
signed main(){
	n=getint();
	m=getint();
	S=getint();
	T=getint();
	for(int re i=1;i<=m;++i){
		int u=getint(),v=getint();
		ll val=getint();
		if(v!=u)
		addedge(u,v,val);
	}
	Dijkstra(distS,cntS,S,T);
	Dijkstra(distT,cntT,T,S);
	tot=distS[T];
	ans=cntS[T]*cntT[S]%mod;
	for(int re u=1;u<=n;++u){
		if(distS[u]+distT[u]!=tot)continue;
		if(distS[u]==distT[u]){
			ans=(ans-cntS[u]*cntT[u]%mod*cntS[u]%mod*cntT[u]%mod+mod)%mod;
			continue;
		}
		if(distS[u]*2>tot)continue;
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
			if(distS[v]!=distS[u]+w[e])continue;
			if(distT[v]*2>=tot)continue;
			if(tot!=distS[u]+w[e]+distT[v])continue;
			ans=(ans-cntS[u]*cntT[v]%mod*cntS[u]%mod*cntT[v]%mod+mod)%mod;
		}
	}
	cout<<(ans%mod+mod)%mod;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章