#同余最短路#洛谷 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);
}