【BZOJ 2118】 墨墨的等式(Dijkstra)

BZOJ2118 墨墨的等式

题链:http://www.lydsy.com/JudgeOnline/problem.php?id=2118

Description

墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N、{an}、以及B的取值范围,求出有多少B可以使等式存在非负整数解。

Input

输入的第一行包含3个正整数,分别表示N、BMin、BMax分别表示数列的长度、B的下界、B的上界。输入的第二行包含N个整数,即数列{an}的值。

Output

输出一个整数,表示有多少b可以使等式存在非负整数解。

Sample Input

2 5 10
3 5

Sample Output

5

HINT

对于100%的数据,N≤12,0≤ai≤5*10^5,1≤BMin≤BMax≤10^12

题解

假设x是一个可以被拼出的可行解,那么(x+ka[i])必然也是可行解,那么我们把a[i]设为最小的a[0]即可,因为这样才能使得k最大。同时我们可以得到:
1) x可以写成k
a[0]+i,(0<=i<a[0])
2) 所以最多只有i个解,我们只需求出每个解的最小代价即可
因此可以建图,每个i与(a[j]+i)%a[0],之间的代价为a[j],之后再求0到每个i之间的距离即可

参考代码

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <vector>
#define ll long long
#define inf 10000000000000
#define mod 1000000007
using namespace std;
ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
const int N=5e5+10;
const int M=5e6+10;
int cnt;
struct Edge{
    int cost,to,nxt;
    Edge(){};
    Edge(int tc,int tt,int tn=0):cost(tc),to(tt),nxt(tn){}
    bool operator < (const Edge &an) const{
        return cost>an.cost;
    }
}Path[M];
int a[20],head[N];
ll dis[N];
bool vis[N];
void Addedge(int u,int v,int w){
    Path[cnt]=(Edge){w,v,head[u]};
    head[u]=cnt++;
}
void Dijkstra()
{
    priority_queue<Edge>que;
    for(int i=0;i<a[0];i++) dis[i]=inf;
    dis[0]=0;
    que.push(Edge(0,0));
    while(!que.empty()){
        int cur=que.top().to;que.pop();
        if(vis[cur])continue;
        vis[cur]=true;
        for(int i=head[cur];i;i=Path[i].nxt)
            if(dis[cur]+Path[i].cost<dis[Path[i].to]){
                dis[Path[i].to]=dis[cur]+Path[i].cost;
                que.push(Edge(dis[Path[i].to],Path[i].to));
            }
    }
}
ll query(ll x)
{
    ll ans=0;
    for (int i=0;i<a[0];i++)
        if (dis[i]<=x) ans+=(x-dis[i])/a[0]+1;
    return ans;
}
void Init(){
    cnt=1;
    memset(head,0,sizeof(head));
}
int main(){
    int top=0,n=read();
    ll l=read(),r=read();
    Init();
    for(int i=0;i<n;i++){
         int x=read();
         if(x==0) continue;
         a[top++]=x;
    }
    sort(a,a+top);
    for(int i=0;i<a[0];i++){
        for(int j=1;j<top;j++){
             Addedge(i,(a[j]+i)%a[0],a[j]);
        }
    }
    Dijkstra();
    printf("%lld\n",query(r)-query(l-1));
    return 0;
}

转载于:https://www.cnblogs.com/zsyacm666666/p/6957224.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值