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

膜意义下最短路。

把最小的\(a\)抠出来,作为模数\(mod\),然后建点编号为\(0\)\(mod-1\),对每个数\(a\)连边\((i,(a+i)\mod mod)\)\(i\)的最短路就是凑出对\(mod\)取膜为\(i\)的最小数

然后随便统计一下

注意判掉0

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int fir[500010],dis[10000010],nxt[10000010],w[10000010],id;
il vd link(int a,int b,int c){nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c;}
int a[500010];
ll dist[500010];bool vis[500010];
std::priority_queue<std::pair<ll,int> >que;
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    int n=gi();ll Bl,Br;scanf("%lld%lld",&Bl,&Br);
    int mod=1e9;
    for(int i=1;i<=n;++i){a[i]=gi();if(a[i])mod=std::min(mod,a[i]);}
    for(int i=1;i<=n;++i)
        for(int j=0;j<mod;++j)
            link(j,(j+a[i])%mod,a[i]);
    memset(dist,63,sizeof dist);
    dist[0]=0;que.push(std::make_pair(0,0));
    while(!que.empty()){
        int x=que.top().second;vis[x]=1;
        for(int i=fir[x];i;i=nxt[i])
            if(dist[dis[i]]>dist[x]+w[i]){
                dist[dis[i]]=dist[x]+w[i];
                que.push(std::make_pair(-dist[dis[i]],dis[i]));
            }
        while(!que.empty()&&vis[que.top().second])que.pop();
    }
    ll ans=0;
    --Bl;
    for(int i=0;i<mod;++i)if(dist[i]!=dist[mod]&&dist[i]<=Bl)ans-=(Bl-i)/mod-(dist[i]-i-1)/mod;
    for(int i=0;i<mod;++i)if(dist[i]!=dist[mod]&&dist[i]<=Br)ans+=(Br-i)/mod-(dist[i]-i-1)/mod;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-12-28 20:30  菜狗xzz  阅读(197)  评论(0编辑  收藏  举报