[NOIP2001 普及组] 数的计算
题目描述
我们要求找出具有下列性质数的个数(包含输入的正整数 nnn)。
先输入一个正整数 nnn(n≤1000n \le 1000n≤1000),然后对此正整数按照如下方法进行处理:
-
不作任何处理;
-
在它的左边拼接一个正整数,但该正整数不能超过原数,或者是上一个被拼接的数的一半;
-
加上数后,继续按此规则进行处理,直到不能再加正整数为止。
输入格式
一行,一个正整数 nnn(n≤1000n \le 1000n≤1000)。
输出格式
一个整数,表示具有该性质数的个数。
样例 #1
样例输入 #1
6
样例输出 #1
6
提示
【样例解释】
满足条件的数为:666,161616,262626,126126126,363636,136136136。
【题目来源】
NOIP 2001 普及组第一题
题解:
首先先推导一下规律:
- 当n=1时,小于等于1/2的整数只有0,非正,所以只有一个1
- 当n=2时,小于等于2/2的正整数有1,因此有2,12两个
- 当n=3时,小于等于3/2的正整数有1,因此有3,13两个
- 当n=4时,小于等于4/2的正整数有1,2,因此有4,14,24,124四个
- 当n=5时,小于等于5/2的正整数有1,2,因此有5,15,25,125四个
- 当n=6时,小于等于6/2的正整数有1,2,3,因此有6,16,26,126,36,136
写到这,应该能看出一些规律了,由于每个数本身就是具有这种性质的数,所以每个数的方法数初始值都是1,然后就枚举能拼接在它旁边的数,由于这些数小于等于原数的一半,所以这些数的情况在之前一定是求过的。
拿n=6来举例,其实26,126,就等价于n=2的情况不是吗?
因此有等式:
f[n] = 1+ f[1] + f[2] + f[3] + … + f[n/2]
代码:
#include <iostream>
using namespace std;
int n; long long f[1002];
int main()
{
cin >> n;
f[1] = 1;
for (int i = 2; i <= n; i++) {
f[i]++;
for (int j = 1; j <= i / 2; j++) {
f[i] += f[j];
}
}
cout << f[n];
return 0;
}

940

被折叠的 条评论
为什么被折叠?



