题面
解法
数学题竟然变成了图论题……
- 将问题转化一下,变成我们需要求 a1x1+a2x2+…anxn=m a 1 x 1 + a 2 x 2 + … a n x n = m 是否存在非负整数解
- 考虑这样一个思路,假设 disi d i s i 表示上述式子对 a1 a 1 取模的结果为 i i ,满足这样一个条件的数的最小值
- 那么,我们就可以对这些数全部当成一个点,然后如果满足 i+aj≡k (mod a1) i + a j ≡ k ( m o d a 1 ) ,那么连接 (i,k) ( i , k ) ,边权为 aj a j
- 这样建边后,用dijkstra算法跑最短路,那么我们就可以求得模 a1 a 1 为任意数的最小值了
- 然后判断 m m 是否可以存在非负整数解,我们只要看模 a1 a 1 对应的余数,然后看 disi d i s i 是否不大于 m m 即可
- 那么,对于一段区间,我们都可以求出模余 i i 的解数
- 时间复杂度:
【后话】
- 和这道题类似地,也可以出这样一个问题:给定 a1,a2…an a 1 , a 2 … a n ,问最大的不能被 a1x1+a2x2+…anxn a 1 x 1 + a 2 x 2 + … a n x n 表示的非负整数是多少。其中 x1,x2,…xn x 1 , x 2 , … x n 必须均为非负整数
- 和这道题一样,可以建出 a1 a 1 个点,求出 disi d i s i 之后满足模 a1 a 1 余 i i 且不能被表示的最大数即为,对这个东西取max即可
- 这个应该是NOIP2017小凯的疑惑这道题的加强版吧
代码
#include <bits/stdc++.h>
#define LL long long
#define PI pair <LL, int>
#define mp make_pair
#define N 500010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Edge {
int next, num, v;
} e[N * 24];
int cnt, a[N], used[N];
LL dis[N];
void add(int x, int y, int v) {
e[++cnt] = (Edge) {e[x].next, y, v};
e[x].next = cnt;
}
void dijkstra(int s, int n) {
for (int i = 1; i <= n; i++) dis[i] = 1ll << 50;
priority_queue <PI, vector <PI>, greater <PI> > h;
dis[s] = 0, h.push(mp(0, s));
while (!h.empty()) {
PI tmp = h.top(); h.pop();
int x = tmp.second;
if (used[x]) continue; used[x] = 1;
for (int p = e[x].next; p; p = e[p].next) {
int k = e[p].num, v = e[p].v;
if (dis[k] > dis[x] + v)
dis[k] = dis[x] + v, h.push(mp(dis[k], k));
}
}
}
LL calc(LL x, int y, int z) {
LL ret = x / y;
if (x % y >= z && x) ret++;
return ret;
}
int main() {
int n, mn = INT_MAX, mni; LL l, r;
read(n), read(l), read(r);
for (int i = 1; i <= n; i++) {
read(a[i]);
if (mn > a[i]) mn = a[i], mni = i;
}
cnt = mn;
for (int i = 1; i <= n; i++) {
if (i == mni) continue;
for (int j = 0; j < mn; j++)
add(j, (j + a[i]) % mn, a[i]);
}
dijkstra(0, mn - 1); LL ans = 0;
for (int i = 0; i < mn; i++) {
LL tl = max(dis[i], l), tr = r;
if (tl > tr) continue;
ans += calc(tr, mn, i) - calc(tl - 1, mn, i);
}
cout << ans << "\n";
return 0;
}