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

 

大概思維退化到這種題目第一發也寫不出來。。。

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