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

传送门

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

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

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

那就跑 s p f a spfa spfa求出所有最小的 x x x就可以了

#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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值