题目
题目描述
我们要求找出具有下列性质数的个数(包含输入的自然数nn):
先输入一个自然数nn(n \le 1000n≤1000),然后对此自然数按照如下方法进行处理:
-
不作任何处理;
-
在它的左边加上一个自然数,但该自然数不能超过
原数新添加的数的一半; -
加上数后,继续按此规则进行处理,直到不能再加自然数为止.
输入格式
1个自然数n(n≤1000)
输出格式
1个整数,表示具有该性质数的个数。
注意点
题目的表述,个人觉得依旧有问题,具体可以参考什么是半数集。
举个例子,求set(10).
10前面可以加上5, 4, 3, 2, 1。当变成510后,还可以再加上2 得到2510,加上1得到1510;当变成410后,还可以再加上1, 2。。。。
代码
直接递归肯定不行,大部分测试点会超时。
可以找个数组标记一下,如果之前计算过,那就直接从数组中取出来。
typedef long long ll;
const int maxn = 1e6+5;
ll mark[maxn];
ll cal(int a)
{
if(a == 1) return 1;
if(mark[a]) return mark[a];
ll res = 1;
for(int i = 1 ; i <= a / 2 ; i ++)
res += cal(i);
mark[a] = res;
return res;
}
int main()
{
int n ; cin >> n;
memset(mark , 0 , sizeof(mark));
cout << cal(n) << endl;
}
在看题解的过程中,有大佬发现了一个小小的规律:
f[1]=1
f[2]=2=f[1]+1
f[3]=2=f[1]+1
f[4]=4=f[1]+f[2]+1
f[5]=4=f[1]+f[2]+1
......
typedef long long ll;
const int maxn = 1e6+5;
ll mark[maxn];
int main()
{
int n ; cin >> n;
mark[1] = 1;
for(int i = 2; i <= maxn ; i ++)
{
if( i % 2 == 1)
mark[i] = mark[i - 1];
else
mark[i] = mark[i / 2] + mark[i - 1];
}
cout << mark[n] << endl;
}
大概思维退化到这种题目第一发也写不出来。。。