[国家集训队]墨墨的等式 [差分约束]

本文介绍了解决墨墨的等式问题的一种高效算法实现——SPFA算法,并详细展示了通过C++代码实现该算法的过程。文章重点在于如何利用SPFA算法求解特定条件下的最短路径问题。

2371 [国家集训队]墨墨的等式

直接放学长的讲解还有代码算了.....

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define rg register
#define ll long long
#define LDB long double
#define ull unsigned long long
#define view(i,x) for(rg int i=hd[x];i!=-1;i=e[i].nt)
#define go(i,x,a) for(rg int i=a;i<x;i++)
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
using namespace std;

const int maxn=5e5+5;
int n,hd[maxn],k,a[maxn],vis[maxn];
ll L,R,dis[maxn];
struct edd{
    int nt,v,w;
}e[maxn*20];

inline ll rd(){
    ll ret=0,af=1; char gc=getchar();
    while(gc < '0' || gc > '9'){ if(gc=='-') af=-af; gc=getchar(); }
    while(gc >= '0' && gc <= '9') ret=ret*10+gc-'0',gc=getchar();
    return ret*af;
}

inline void add(int a,int b,int c){
    e[k].v=b; e[k].w=c; e[k].nt=hd[a]; hd[a]=k++;
}

void spfa(){
    memset(dis,-1,sizeof(dis));
    deque<int>q;
    /*go(i,n+1,1){
        int x=a[i]%a[1];
        if(dis[x] == -1) dis[x]=a[i],q.push_back(x),vis[x]=1;
        else dis[x]=min(dis[x],(ll)a[i]);
    }*/
    q.push_back(0); vis[0]=1; dis[0]=0;
    while(!q.empty()){
        int x=q.front(); q.pop_front(); vis[x]=0;
        for(rg int i=hd[x];i!=-1;i=e[i].nt){
            int v=e[i].v,w=e[i].w;
            if(dis[v] == -1 || dis[v] > dis[x]+w){
                dis[v]=dis[x]+w;
                if(!vis[v]){
                    if(q.empty()) q.push_back(v);
                    else if(dis[v] < dis[q.front()]) q.push_front(v);
                         else q.push_back(v);
                    vis[v]=1;
                }
            }
        }
    }
}

inline ll cal(ll m){
    ll ans=0;
    go(i,a[1],0){
        if(dis[i] > m || dis[i] == -1) continue;
        ans=ans+(m-dis[i])/a[1]+1;
    }
    return ans;
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("3.in","r",stdin);
    //freopen(".out","w",stdout);
    #endif
    memset(hd,-1,sizeof(hd)); k=0;
    n=rd(); L=rd(); R=rd();
    go(i,n+1,1) a[i]=rd();
    sort(a+1,a+n+1);
    go(i,a[1],0)
        go(j,n+1,2) 
            add(i,(i+a[j])%a[1],a[j]);
    spfa();
    printf("%lld",cal(R)-cal(L-1));
    return 0;
}//Faze

 

转载于:https://www.cnblogs.com/lxyyyy/p/11216003.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值