同余最短路,考虑直接用最小的代价拼出来在膜最小 \(a_i\) 意义下的余数。然后不停地累加最小的 \(a_i\)(一下称它 \(a_{min}\)) 就行了。
正确性:假定 \(i,j,k\) 为膜 \(a_{min}\) 下的余数,令 \(i+j \equiv k (\mod a_{min})\) 那么显然 \(i+j = t \cdot a_{min} + k\) (\(t\) 为任意非负整数)
那么在 \(k + t \cdot a_{min}\) 一定可以全覆盖 \((i+j) + t \cdot a_{min}\)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll MAXN = 6e6+10;
const ll MAXM = 5e5+10;
struct edge {
ll nt, to, v;
} E[MAXN];
ll a[MAXM], N, head[MAXM], cnt = -1, vis[MAXM], dis[MAXM], L, R, ans;
void add(ll, ll, ll);
void spfa(ll);
int main() {
memset(head, -1, sizeof(head));
scanf("%lld%lld%lld", &N, &L, &R); L--;
for (ll i = 1; i <= N; i++) scanf("%lld", a+i);
sort(a+1, a+N+1);
for (ll i = 0; i < a[1]; i++) for (ll j = 1; j <= N; j++) add(i, (i + a[j]) % a[1], a[j]);
spfa(0);
for (ll i = 0; i < a[1]; i++) {
if (dis[i] <= L) ans -= ((L - dis[i]) / a[1]) + 1;
if (dis[i] <= R) ans += ((R - dis[i]) / a[1]) + 1;
}
printf("%lld\n", ans);
return 0;
}
void spfa(ll st) {
queue <ll> q;
q.push(st);
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
vis[st] = 1;
dis[st] = 0;
while (!q.empty()) {
ll nt = q.front();
q.pop();
vis[nt] = 0;
for (ll i = head[nt]; ~i; i = E[i].nt) {
ll v = E[i].to;
if (dis[v] > dis[nt] + E[i].v) {
dis[v] = dis[nt] + E[i].v;
if (!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
}
void add(ll x, ll y, ll v) {
cnt++;
E[cnt].to = y;
E[cnt].nt = head[x];
E[cnt].v = v;
head[x] = cnt;
}