JZOJ4722. 跳楼机
题目大意
问\(0\)~\(h-1\)中, 有多少整数可以表示成\(ax+by+cz\)的形式, 其中\(a,b,c\in\mathbb{N}, x,y,z\in\mathbb{N^*}\), 给出\(x,y,z\), 且\(x,y,z<=10^5\), \(h<=10^{18}\).
解题思路
首先\(--h\), 方便处理.
本来以为这是一道数学题.. 绞尽脑汁希望用自己浅薄的数学知识完成这道题, 最后当然是不了了之..
设\(K\)是表示出来的数集, \(k\)是其中的一个数.
把\(k\)按照\(\operatorname{mod} {x}\)分类(小声BB:其实我也想到了), 设\(d_i\)表示\(\operatorname{mod} {x} = i\)的最小\(k\).
显然最后的答案就是 \(\sum_0^{x-1}[d_i<=h](\lfloor\frac{h-d_i}{x}\rfloor+1)\).(因为\(d_i+x, d_i+2*x..\)都是可以表示出来的)
\(d_i\)如何求? 是通过\(y\)和\(z\)求出的. 其实这相当于模意义下的最短路. (听说叫同余最短路)
很难想到, 但是确实比较妙. 以后也多了这方面的经验.
#include <queue>
#include <cstdio>
#include <algorithm>
#define ll long long
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
using namespace std;
ll h, x, y, z, ans, d[100010];
bool inq[100010];
queue<int> q;
void upd(int u, int k)
{
int v = (u + k) % x;
if(d[v] > d[u] + k) d[v] = d[u] + k, !inq[v] && (q.push(v), inq[v] = 1);
}
int main()
{
scanf("%lld%lld%lld%lld", &h, &x, &y, &z); --h;
fo(i, 1, x - 1) d[i] = 0x3f3f3f3f3f3f3f3fll;
q.push(0); inq[0] = 1;
while(!q.empty())
{
int u = q.front(); q.pop(); inq[u] = 0;
upd(u, y); upd(u, z);
}
fo(i, 0, x - 1) if(h >= d[i]) ans += (h - d[i]) / x + 1;
printf("%lld\n", ans);
return 0;
}
浙公网安备 33010602011771号