题解: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) 收藏 举报