洛谷P1748 H数 题解
题目链接:P1748 H数
题意:
所谓 $H$ 数,是指只含有 $2,3,5,7$ 这些质因数的数,如 $630$ 是 $H$ 数,而 $22$ 不是。
现在要求输出第 $n$ 个 $H$ 数,即 $H_n$ (为了方便起见将 $H_1$ 定为 $1$ )。
已知 $n$ 不超过 $10000$,最后数据在 int64 范围之内。
输入格式:
一行, $n$ 。
输出格式:
一行,输出 $H_n$ 。
虽说是 普及/提高− 的题,但是它的思路还是挺有意思的。
考虑dp,或者说考察 $H_n$ 的递推方式。
其中 $a,b,c,d$ 均满足特定形式,例如 $H_{a-1}\times 2 \le H_i < H_a \times 2$ 。
一种暴力的转移方式是,枚举 $j$ ,并钦定:例如当 $j$ 满足 $a$ 的条件时尝试用 $H_a$ 更新 $H_i$ 。
这样只需扫一遍 $[1,~i-1]$ 即可。注意到 $a,b,c,d$ 均随着 $i$ 的增长而不减。
因此我们可以直接维护四个指针 $a,b,c,d$ ,每次算出 $H_i$ 后,更新 $a,b,c,d$ 使他们重新满足条件。
时间复杂度 $\mathcal{O}(n)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e4 + 15))
int a,b,c,d,x[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n; cin >> n; x[1] = a = b = c = d = 1;
for(int i = 2; i <= n; i++)
{
x[i] = x[a] * 2;
if(x[i] > x[b] * 3) x[i] = x[b] * 3;
if(x[i] > x[c] * 5) x[i] = x[c] * 5;
if(x[i] > x[d] * 7) x[i] = x[d] * 7;
if(x[i] == x[a] * 2) ++a;
if(x[i] == x[b] * 3) ++b;
if(x[i] == x[c] * 5) ++c;
if(x[i] == x[d] * 7) ++d;
}
cout << x[n] << '\n';
return 0;
}
参考文献:
[1] https://www.luogu.com.cn/blog/user41920/solution-p1748
题外话:
这和 H 有什么关系?