題目
題目描述
我們要求找出具有下列性質數的個數(包含輸入的自然數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;
}
大概思維退化到這種題目第一發也寫不出來。。。