10.27练习题 托马斯小火车

10.27练习题 托马斯小火车

KONO题面哒!

问题描述
随着全 损 音 质的托马斯主题曲响起,托马斯小火车开始飙车啦!托马斯所在的城镇可看做一个由n个点m条边构成的无向图,每条边都有一定的长度。图中有两辆自带全 损 音 质主题曲的托马斯甲和托马斯乙。甲从A点沿最短路走向B点,乙从B点沿最短路走向A点。 甲乙两辆托马斯之间存在无法预测的量子纠缠,他们路途中相遇就会飙歌。
问,有多少种走法,城镇中的居民不会受到全 损 音 质的噪音污染。 相遇是指同在某个点或者某条边上相遇。 答案可能很大,mod 10^9+7后再输出。

输入格式
第一行,两个整数n,m 第二行,两个整数A,B 接下来m行,每行三个整数x,y,z,表示点x与点y间有一条长z的边。
输出格式
一个整数,表示方案数。

样例输入1
4 4
1 3
1 2 1
2 3 1
3 4 1
4 1 1
样例输出1
2

样例输入2
8 13
4 2
7 3 9
6 2 3
1 6 4
7 6 9
3 8 9
1 2 2
2 8 12
8 6 9
2 5 5
4 2 18
5 3 7
5 1 515371567
4 8 6
样例输入2
6

数据范围
对于 100% 的数据,1 ≤ n ≤100000 1 ≤ m ≤200000 1≤z≤10^9 图连通,且没有重边


一直在挣扎A,C。看了(其实是听了)之后才发现这是道大水题)


考察点:最短路 容斥
两次 \(dijkstra\) 求出 A 到 B 和 B 到 A 的最短路,设最短路长度为\(LenAB\)
在进行 \(dijkstra\) 的过程中,记录下列信息:
从 A 到点 i 的最短距离记为 \(DisA[i]\),从 A 到 i 的最短路线数量\(CntA[i]\)
从 B 到点 i 的最短距离记为 \(DisB[i]\),从 B 到 i 的最短路线数量\(CntB[i]\)
考虑用容斥原理求解答案:总方案数-不合法方案数
总方案数 \(Tot=CntA[B]*CntB[A]\)
不合法方案:
1.若在 i 号点相遇:\(DisA[i]+DisB[i]=LenAB\)\(DisA[i]==DisB[i]\)
方案数=\(CntA[i]*CntB[i]*CntB[i]*CntA[i]=(CntA[i]*CntB[i])^2\)
\(CntA[i]*CntB[i]\)只是表示走到相汇点 i 的方案数。剩下的路还要继续走,所以还要乘以\(CntA[i]*CntB[i]\)
2.若在 i 号边中相遇,设边的两个端点为 x,y:
\(DisA[x]+Len[i]+DisB[y]=LenAB\)\(DisA[x]+Len[i]>DisB[y]\)\(DisB[y]+Len[i]>DisA[x]\)
方案数=\((CntA[x]*CntB[y])^2\)


KONO代码哒!

#include<cmath>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
struct edge{
    int from,to,next,dis;
}g[400010];
typedef long long ll;
const ll maxn=100010;
const ll inf=0x3f3f3f3f;
const ll mod=1e9+7;
ll head[maxn],cnt;
ll n,m,A,B;
ll num[2][maxn],dis[2][maxn];
void add(ll from,ll to,ll dis)
{
    g[++cnt].next=head[from];
    g[cnt].to=to;
    g[cnt].dis=dis;
    g[cnt].from=from;
    head[from]=cnt;
}
struct node{
    ll to,dis;
};
bool operator<(node a,node b)
{
    return a.dis>b.dis;
}
priority_queue<node>q;
bool mark[maxn];
void dij(ll x,ll pos)
{
    memset(mark,0,sizeof(mark));
    dis[pos][x]=0;
    num[pos][x]=1;
    q.push((node){x,0});
    while(q.size())
    {
        ll u=q.top().to;
        q.pop();
        if(mark[u])continue;
        mark[u]=1;
        for(ll i=head[u];i;i=g[i].next){
            ll v=g[i].to,d=g[i].dis;
            if(!mark[v]&&dis[pos][u]+d<dis[pos][v]){
                num[pos][v]=num[pos][u];
                dis[pos][v]=dis[pos][u]+d;
                q.push((node){v,dis[pos][v]});
            }
            else if(dis[pos][u]+d==dis[pos][v]){
                num[pos][v]=(num[pos][v]+num[pos][u])%mod;
            }
        }
    }
}
ll pow(ll x)
{
    return (x%mod)*(x%mod)%mod;
}
ll reduce(ll a,ll b)
{
    return ((a-b)%mod+mod)%mod;
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>m>>A>>B;
    ll i,j;
    for(i=1;i<=m;i++){
        ll x,y,z;
        cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
    }
    memset(dis,0x3f,sizeof(dis));
    // for(i=1;i<=n;i++)num[0][i]=num[1][i]=1;
    dij(A,0);
    dij(B,1);
//    for(i=0;i<=1;i++)
//    {
//        for(j=1;j<=n;j++)
//        {
//            printf("%lld %lld\n",dis[i][j],num[i][j]);
//        }
//    }
    ll len=dis[0][B];
    ll ans=(num[0][B]*num[1][A])%mod;
//    printf("%lld\n",ans);
    for(i=1;i<=n;i++)
    {
        if(dis[0][i]+dis[1][i]==len&&dis[0][i]==dis[1][i]){
            ans=reduce(ans,pow(num[0][i]*num[1][i]));
        }
    }
//    printf("%lld\n",ans);
    for(i=1;i<=cnt;i++)
    {
        int f=g[i].from,t=g[i].to,d=g[i].dis;
        if(dis[0][f]+d+dis[1][t]==len&&dis[0][f]+d>dis[1][t]&&dis[1][t]+d>dis[0][f])
        {
            ans=reduce(ans,pow(num[0][f]*num[1][t]));
        }
    }
    printf("%lld\n",ans);
}

(直接贴的solution,先去搞一搞服务器的事,之后再用沙雕语言详细写)
enter description here


posted @ 2019-10-28 19:13  国土战略局特工  阅读(320)  评论(0)    收藏  举报