问题H - 数的计数
题目来源:NOIP 2001 普及组 T1/4
题目描述
原题面
给出正整数 \(n\),要求按如下方式构造数列:
- 只有一个数 \(n\) 的数列是一个合法的数列。
- 在一个合法的数列的末尾加入一个正整数,但是这个正整数不能超过该数列最后一项的一半,可以得到一个新的合法数列。
请你求出,一共有多少个合法的数列。两个合法数列 \(a, b\) 不同当且仅当两数列长度不同或存在一个正整数 \(i \leq |a|\),使得 \(a_i \neq b_i\)。
对于全部的测试点,保证 \(1 \leq n \leq 10^3\)。
Info
注意此题原题表达有歧义。如当 \(n = 245\) 时,有 \(11|22|245\) 和 \(1|122|245\) 这样的情况。这样的情况应算作 \(2\) 种情况。
输入要求
输入只有一行一个整数,表示 \(n\)。
输出要求
输出一行一个整数,表示合法的数列个数。
样例
满足条件的数列有:\((6)\)、\((6, 1)\)、\((6, 2)\)、\((6, 3)\)、\((6, 2, 1)\)、\((6, 3, 1)\)。
解法
记忆化搜索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | #include <bits/stdc++.h>
#define lli long long int
using namespace std;
const int MAXn = 1e3 + 9;
lli d[MAXn]; // d[i]: 以 i 开始的所有情况
void f(int x) {
for(int y = 0; y <= (x >> 1); y ++) {
if(!d[y]) f(y);
d[x] += d[y];
}
}
int main() {
d[0] = 1;
int n;
scanf("%d", &n);
f(n);
printf("%lld", d[n]);
return 0;
}
|
动态规划
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include <bits/stdc++.h>
#define lli long long int
using namespace std;
const int MAXn = 1e3 + 9;
lli d[MAXn]; // d[i]: 以 [1, i] 开始的所有情况,类似前缀和
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
d[i] = d[i - 1] + d[i >> 1] + 1;
printf("%lld", d[n >> 1] + 1);
// printf("%lld", d[n] - d[n - 1]);
return 0;
}
|