【BZOJ2118】—墨墨的等式(最短路+背包)

传送门

考虑到其实这就是一个背包问题,但是发现BB的范围太大了
考虑另外的做法

我们发现对于一个数xx,如果xx可以凑出来,那么x+kaix+ka_i显然都可以凑出来
而且可以凑出(MaxBx)/ai+1(MaxB-x)/a_i+1
为了让求的量最少,我们用最小的aia_i

那么那现在我们也就只需要找到最小的xx满足B%ai=xB\%a_i=x就可以了
发现可以最短路求

那就跑spfaspfa求出所有最小的xx就可以了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
const ll inf=1e13;
inline ll read(){
    char ch=getchar();
    ll res=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return res;
}
const int N=500005;
int vis[N],a[N],n,mox;
ll L,R,dis[N];
inline void spfa(){
	queue<int> q;
	vis[0]=1,dis[0]=0;
	q.push(0);
	while(!q.empty()){
		int u=q.front();q.pop(),vis[u]=0;
		for(int i=1;i<=n;i++){
			int v=(u+a[i])%mox;
			if(dis[u]+a[i]<dis[v]){
				dis[v]=dis[u]+a[i];
				if(!vis[v]){
					q.push(v),vis[v]=1;
				}
			}
		}
	}
}
inline ll calc(ll mx){
	ll ans=0;
	for(int i=0;i<mox;i++){
		if(dis[i]<=mx)
		ans+=(mx-dis[i])/mox+1;
	}
	return ans;
}
int main(){
	n=read(),L=read(),R=read();
	mox=1e9;
	for(int i=1;i<=n;i++){
		a[i]=read();
		if(a[i]==0){i--,n--;continue;}
		mox=min(mox,a[i]);
	}
	memset(dis,127/3,sizeof(dis));
	spfa();
	cout<<calc(R)-calc(L-1);
}
posted @ 2019-02-16 20:12  Stargazer_cykoi  阅读(152)  评论(0编辑  收藏  举报