题目描述:
给出$h,x,y,z$,求在$h$以内,$x,y,z$可以凑出多少个不同的数。$(1\leq{h}\leq{10^{18}},1\leq{x,y,z}\leq{10^5})$
解题思路:
直接做显然不好做。我们考虑取$n$个$y$和$m$个$z$,然后再加上$x,2*x,3*x\cdots$,显然地,只要对于每种取法,$(ny+mz)\%x$的值不同的话,就不会有重复。所以我们先求出$d_{i}=c$表示通过选$y$和$z$使得和模$x$等于$i$的最小和$c$。然后答案就是$\sum_{i=0}^{x-1}(\lfloor\frac{h-d_{i}}{x}\rfloor+1)$。至于怎么求$d_{i}$,可以发现$d_{(i+y)\%x}=d_{i}+y$,$d_{(i+z)\%x}=d_{i}+z$,明显的最短路模型。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define i64 long long 6 using namespace std; 7 8 const int N = 1e5 + 10; 9 const i64 inf = 1e18 + 1; 10 int x, y, z, inq[N]; 11 i64 h, ans, d[N]; 12 13 queue <int> q; 14 15 void spfa() { 16 for (int i = 0; i < x; i ++) d[i] = inf; 17 d[1] = 1 % x; 18 q.push(1); 19 inq[1] = 1; 20 while (!q.empty()) { 21 int i = q.front(); q.pop(); 22 if (d[i] + y < d[(i + y) % x]) { 23 d[(i + y) % x] = d[i] + y; 24 if (!inq[(i + y) % x]) { 25 inq[(i + y) % x] = 1; 26 q.push((i + y) % x); 27 } 28 } 29 if (d[i] + z < d[(i + z) % x]) { 30 d[(i + z) % x] = d[i] + z; 31 if (!inq[(i + z) % x]) { 32 inq[(i + z) % x] = 1; 33 q.push((i + z) % x); 34 } 35 } 36 inq[i] = 0; 37 } 38 } 39 40 int main() { 41 scanf("%lld", &h); 42 scanf("%d %d %d", &x, &y, &z); 43 spfa(); 44 for (int i = 0; i < x; i ++) if (h > d[i]) ans += (h - d[i]) / x + 1; 45 printf("%lld", ans); 46 return 0; 47 }