CSP歷年複賽題-P1028 [NOIP2001 普及組] 數的計算

江城伍月發表於2024-05-21

原題連結:https://www.luogu.com.cn/problem/P1028

題意解讀:給定n,構造數列,可以用遞迴或者遞推。

解題思路:

1、遞迴

定義count(n)返回數列的個數

  n==1時,count(n) = 1

  n!=1時,count(n) = 1 + count(1) + count(2) + ...+ count(n/2)

注意,遞迴會導致大量重複計算,需要用一個hash陣列來避免重複計算,否則會超時

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 3005;

long long f[N];

int n;

long long count(int n)
{
    if(f[n]) return f[n]; //如果count(n)已經計算過,直接返回結果
    if(n == 1) return 1;
    long long res = 1;
    for(int i = 1; i <= n / 2; i++)
    {
        res += count(i);
    }
    f[n] = res; //將count(n)的值儲存下來,避免重複計算
    return res;
}

int main()
{
    cin >> n;
    cout << count(n);
    return 0;
}

2、遞推

我們看n = 6,數列為:

6

6,1

6,2

6,3

6,2,1

6,3,1

n = 5時,數列為:

5

5,1

5,2

5,2,1

相比n=6,缺少了n=3的數列

n=4時,數列為:

4

4,1

4,2

4,2,1

與n=5時一樣。

因此,可以推斷,令f[i]為i的數列數量

當i是偶數時,f[i] = f[i - 1] + f[i / 2]

當i是奇數時,f[i] = f[i - 1]

初始值f[1] = 1

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 3005;

long long f[N];
int n;

int main()
{
    cin >> n;
    f[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(i % 2 == 0) f[i] = f[i - 1] + f[i / 2];
        else f[i] = f[i - 1];
    }
    cout << f[n];
}

相關文章