1. 程式人生 > >【2018/11/05測試T2】規避

【2018/11/05測試T2】規避

【題目】

傳送門


【分析】

比較妙的一道題

其實直接統計不相遇的情況是比較困難的,以正難則反的思想,我們不如直接統計出總數和相遇的情況,一減就是答案

首先,跑最短路(跑兩遍,從 ss 開始跑一遍,記在 d1d_1 中,從 tt 開始跑一遍,記在 d2d_2 中),並統計出最短路數量(假設為 xx),那總方案數就是 x2x^2(小 Bxx 種走法,小 Z 也有 xx 中)

然後呢,由於速度相同,他們相遇的位置一定是在路徑的中點(就是邊權總和除以 22 的位置)

那麼,現在就分情況討論:

  • 他們在一個點相遇,條件是 d1[i]=d2[i]d_1[i]=d_2[i]
    ,那麼這種走法的方案數就是 (num1[i]num2[i])2(num_1[i]*num_2[i])^2numnum 就是最短路數量
  • 他們在邊上的一點相遇(假設為 (u,v)(u,v)),條件是 d1[v]>d2[v]d_1[v]>d_2[v]d1[u]<d2[u]d_1[u]<d_2[u],方案數為 (num1[u]num2[v])2(num_1[u]*num_2[v])^2

因此我們列舉點和邊,以上面的兩種操作統計合法方案,做完之後減一下就是答案了


【程式碼】

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 500005
#define Mod 1000000007
using namespace std;
int n,m,s,t,tot;
int d[2][N],num[2][N];
int first[N],v[M],w[M],nxt[M];
bool vis[
N]; priority_queue<pair<int,int> >q; void add(int x,int y,int z) { tot++; nxt[tot]=first[x]; first[x]=tot; v[tot]=y; w[tot]=z; } void dijkstra(int s,int k) { int x,y,i; num[k][s]=1; memset(vis,false,sizeof(vis)); memset(d[k],127/3,sizeof(d[k])); q.push(make_pair(0,s));d[k][s]=0; while(!q.empty()) { x=q.top().second;q.pop(); if(vis[x])continue;vis[x]=true; for(i=first[x];i;i=nxt[i]) { y=v[i]; if(d[k][y]>d[k][x]+w[i]) { num[k][y]=num[k][x]; d[k][y]=d[k][x]+w[i]; q.push(make_pair(-d[k][y],y)); } else if(d[k][y]==d[k][x]+w[i]) num[k][y]=(num[k][x]+num[k][y])%Mod; } } } int main() { // freopen("access.in","r",stdin); // freopen("access.out","w",stdout); int x,y,z,i,j; scanf("%d%d",&n,&m); scanf("%d%d",&s,&t); for(i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); add(x,y,z),add(y,x,z); } dijkstra(s,0); dijkstra(t,1); long long sum=1ll*num[0][t]*num[0][t]%Mod; for(i=1;i<=n;++i) { if(d[0][i]+d[1][i]!=d[0][t]) continue; if(d[0][i]==d[1][i]) sum=(sum-1ll*num[0][i]*num[0][i]%Mod*num[1][i]%Mod*num[1][i]%Mod+Mod)%Mod; for(j=first[i];j;j=nxt[j]) { int to=v[j]; if(d[0][i]+w[j]+d[1][to]!=d[0][t]) continue; if(d[0][to]>d[1][to]&&d[0][i]<d[1][i]) sum=(sum-1ll*num[0][i]*num[0][i]%Mod*num[1][to]%Mod*num[1][to]%Mod+Mod)%Mod; } } printf("%lld",sum); // fclose(stdin); // fclose(stdout); return 0; }