【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*105,1≤BMin≤BMax≤1012

题解

假设x是一个可以被拼出的可行解,那么(x+k*a[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;
}

posted @ 2017-06-07 15:16  江南何采莲  阅读(178)  评论(0编辑  收藏  举报