#同余最短路#洛谷 2371 [国家集训队]墨墨的等式

题目

墨墨突然对等式很感兴趣,他正在研究 \(\sum_{i=1}^n a_ix_i=b\) 存在非负整数解的条件,

他要求你编写一个程序,给定 \(n, a_{1\dots n}, l, r\),求出有多少 \(b\in[l,r]\) 可以使等式存在非负整数解。


分析

选取一个较小的数\(m\),设\(dis[x]\)表示得到的最小数在模\(m\)意义下为\(x\)
那么在\([l,r]\)内答案为\(\sum (r-dis[x])/m-(l-1-dis[x])/m\)


代码

#include <cstdio>
#include <cstring>
#include <queue>
#define rr register
using namespace std;
const int N=5000011;
long long dis[N],v[N],l,r,ans;
int mn=N,n,a[21],T; queue<int>q;
signed main(){
	scanf("%d%lld%lld",&T,&l,&r);
	for (rr int x;T;--T){
		scanf("%d",&x);
		if (!x) continue;
		a[++n]=x,mn=mn>x?x:mn;
	}
	memset(dis,0x3f,sizeof(dis)),
	dis[0]=0,q.push(0),v[0]=1;
	while (!q.empty()){
		rr int x=q.front(); q.pop();
		for (rr int i=1;i<=n;++i){
		    rr int z=(x+a[i])%mn;
			if (dis[z]>dis[x]+a[i]){
				dis[z]=dis[x]+a[i];
				if (!v[z]) v[z]=1,q.push(z);
			}
		}
		v[x]=0;
	}
	for (rr int i=0;i<mn;++i)
	if (dis[i]^dis[mn]){
		if (dis[i]<=r) ans+=(r-dis[i])/mn+1;
		if (dis[i]<l) ans-=(l-dis[i]-1)/mn+1;
	}
	return !printf("%lld",ans);
}
posted @ 2021-03-05 19:42  lemondinosaur  阅读(62)  评论(0编辑  收藏  举报