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

题目

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

他要求你编写一个程序,给定 (n, a_{1dots n}, l, r),求出有多少 (bin[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);
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14488120.html