P1028 数的计算 【半数集】【递归】

题目

题目描述

我们要求找出具有下列性质数的个数(包含输入的自然数nn):

先输入一个自然数nn(n \le 1000n≤1000),然后对此自然数按照如下方法进行处理:

  1. 不作任何处理;

  2. 在它的左边加上一个自然数,但该自然数不能超过原数新添加的数的一半;

  3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止.

输入格式

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;
}

 

大概思维退化到这种题目第一发也写不出来。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章