【NOIP 校内模拟】T2 规避(容斥+最短路计数)

可以先不管符合条件的 先统计出所有的可能走法(最短路条数*最短路条数) 然后减去会相遇的

会相遇的分为在点相遇和在边相遇

在点(设为p)相遇:先保证点在最短路上 然后从s到p的最短路等于从t到p的最短路

在边(设为(x,y,z))相遇:同样需要保证边在最短路上(需要判断三次 同样玄妙♂) 以及相遇的地方一定在边上(两条不同的最短路的两倍不超过总长 这个姿♂势可以记住) 挺玄妙的

#include<bits/stdc++.h>
#define mod 1000000007
#define N 100005
#define M 200005
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
template<class T>
inline void read(T &x)
{
    x=0; int f=1;
    static char ch=getchar();
    while((!isdigit(ch))&&ch!='-')  ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    while(isdigit(ch))  x=x*10+ch-'0',ch=getchar();
    x*=f;
}
struct Edge
{
    int from,to,next;
    ll val;
}edge[2*M],res[2*M];
int n,m,first[N],tot,s,t;
inline void addedge(int x,int y,int z)
{
    tot++;
    edge[tot].from=x; edge[tot].to=y; edge[tot].next=first[x]; edge[tot].val=z; first[x]=tot;
}
typedef pair<ll,int> Pair;
ll cnt[N][3],dis[N][3];
int visit[N];
void dijkstra(int S,int f)
{
    memset(visit,0,sizeof(visit));
    priority_queue<Pair,vector<Pair>,greater<Pair> > heap;
    heap.push(make_pair(0,S)); dis[S][f]=0; cnt[S][f]=1;
    while(!heap.empty())
    {
        int now=heap.top().second;
        heap.pop();
        if(visit[now])  continue;
        visit[now]=1;
        for(int u=first[now];u;u=edge[u].next)
        {
            int vis=edge[u].to;
            if(dis[now][f]+edge[u].val<dis[vis][f])
            {
                cnt[vis][f]=cnt[now][f];
                dis[vis][f]=dis[now][f]+edge[u].val;
                heap.push(make_pair(dis[vis][f],vis));
            }
            else if(dis[now][f]+edge[u].val==dis[vis][f])
                cnt[vis][f]=(cnt[vis][f]+cnt[now][f])%mod;
        }
    }
}
int main()
{
//  freopen("evade.in","r",stdin);
    read(n),read(m),read(s),read(t);
    for(int i=1,x,y,z;i<=m;i++) 
    {
        read(x),read(y),read(z);
        addedge(x,y,z); addedge(y,x,z);
    }
    memset(dis,0x3f,sizeof(dis));
    dijkstra(s,1); dijkstra(t,2);
    ll ans=cnt[t][1]*cnt[t][1]%mod,len=dis[t][1];   //总方案数
    for(int i=1;i<=n;i++)   //先判断点
    {
        if(dis[i][1]+dis[i][2]!=len)    continue;   //不在最短路上 
        if(dis[i][1]==dis[i][2])
        {
            ans=((ans-cnt[i][1]*cnt[i][1]%mod*cnt[i][2]*cnt[i][2]%mod)%mod+mod)%mod;
            continue;
        }
        if(dis[i][1]*2>=len)    continue;   //保证在边上 
        for(int u=first[i];u;u=edge[u].next)
        {
            int vis=edge[u].to;
            if(dis[vis][2]*2>=len)  continue;
            if(len!=dis[i][1]+edge[u].val+dis[vis][2])  continue;    //不在最短路上
            ans=((ans-cnt[i][1]*cnt[vis][2]%mod*cnt[i][1]*cnt[vis][2]%mod)%mod+mod)%mod;        
        }
    }
    cout<<(ans%mod+mod)%mod;
    return 0;
}

转载于:https://www.cnblogs.com/Patrickpwq/articles/9909986.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOIP(全国青少年信息学奥林匹克竞赛)是中国国内最高水平的信息学竞赛之一,是计算机领域的重要赛事。针对NOIP模拟题,通常是为了帮助参赛者熟悉比赛形式和题型,提供足够的训练机会。 数据下载是NOIP比赛中的一个重要环节,因为参赛者需要根据提供的数据集进行程序开发和测试。数据下载一般通过网络进行,参赛者需要在指定的时间段内下载数据集到自己的计算机上。 在进行NOIP模拟题数据下载时,我们可以按照以下步骤进行操作: 1. 确认下载链接:NOIP官方会提供下载数据集的链接或者FTP地址,参赛者需要确认链接是否可用和正确。 2. 选择下载工具:根据自己的需求,参赛者可以选择合适的下载工具进行操作。常见的下载工具有浏览器内置下载工具、迅雷、IDM等,可以根据个人的习惯和需求选择合适的下载工具。 3. 打开下载工具:根据所选择的下载工具类型,打开对应的软件,进入下载界面。 4. 输入下载链接:将NOIP提供的数据集下载链接复制粘贴到下载工具的链接输入框中,点击确定或开始进行下载。 5. 等待下载完成:根据数据集的大小和网络速度不同,下载时间会有所变化。参赛者需要耐心等待下载完成,确保数据集完整地保存到自己的计算机上。 6. 验证数据完整性:下载完成后,参赛者需要验证数据集的完整性,确保所有文件都成功地保存到指定位置。可以进行文件大小的比对或者逐个文件的校验来检查数据完整性。 通过以上步骤,参赛者可以成功地进行NOIP模拟题数据的下载。在实际比赛中,一个高效的数据下载过程可以提高参赛者的准备时间和竞争力,确保能够充分利用所提供的数据集进行开发和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值