题解:P1028 [NOIP 2001 普及组] 数的计算

咕了好久……

闲话

建议将网页放大至 125%。


计数题优先考虑 dp。

dp 状态即 \(f_i\) 表示出现一个 \(i\) 后后面的答案。

转移公式易得为:

\[f_i = \sum^{j = 1}_{\lfloor \frac{i}{2} \rfloor} + 1 \]

这里稍作解释,求和即为枚举接下来放什么,后面加一即为后面不加。

代码复杂度为 \(O(n^ 2)\)

#include<bits/stdc++.h>
using namespace std;
int n, f[1005];
int main(){
	cin >> n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= i / 2; j ++) f[i] += f[j];
		f[i] ++;
	}
	cout << f[n];
	return 0;
}

拓展

\(n \le 2 \times 10^5\),原方法将超时,可对 \(f\) 做前缀和,若 \(sum\) 为前缀和数组,转移方程变为:

\[f_i = sum_{i / 2} + 1 \]

代码复杂度为 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
int n, f[1005], sum[1005];
int main(){
	cin >> n;
	for(int i = 1; i <= n; i ++){
		f[i] += sum[i / 2] + 1;
		sum[i] = sum[i - 1] + f[i];
	}
	cout << f[n];
	return 0;
}

posted on 2025-02-28 21:33  zhangzirui66  阅读(40)  评论(0)    收藏  举报

导航