51nod 1201 整数划分

51nod 1201 整数划分

设状态 \(dp[i][j]\) 为和为 \(i\) 时,选择的最大值为 \(j\) 的方案数,所以有转移方程 \(dp[i][j]=dp[i-j][j-1]+dp[i][j-1]\)

有点坑,先枚举 \(j\) 后枚举 \(i\)

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

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n;
int dp[500][500];
int main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<=n;i++){
dp[0][i]=1;
}
for(int j=1;j<=n;j++){
for(int i=1;i<=n;i++){
if(i<j){
dp[i][j]=dp[i][j-1];
}
else{
dp[i][j]=dp[i-j][j-1]+dp[i][j-1];
}
}
}
cout<<dp[n][n];
return 0;
}

考虑优化状态,设状态为 \(dp[i][j]\) 为数字和为 \(i\),选了 \(j\) 个不同的数字方案数。

因为 \(j\)不同所以 \(j\) 最大也只能到 \(\sqrt{n}\),合理,如何转移,一个数肯定可以由他所以组成的数全部减1后得到的那个数转移过来(反过来就是他全部组成的数全加一),即\(dp[i-j][j]\),但可以想到可能 \(1\) 会减为 \(0\),所以我们还要加上那个数本身没有 \(1\) 加完后得到 \(1\) 的方案数,即 \(dp[i-j][j-1]\),递推完求 \(dp[n][i]\) 的累加和。

时间复杂度 \(O(n\sqrt{n})\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
int n;
ll dp[50002][320];
int main() {
ios::sync_with_stdio(false);
cin>>n;
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=320;j++){
if(i>=j){
dp[i][j]=(dp[i-j][j]+dp[i-j][j-1])%mod;
dp[i][j]%=mod;
}
}
}
ll ans=0;
for(int i=1;i<=320;i++){
ans=(ans+dp[n][i])%mod;
}
cout<<ans;
return 0;
}
posted @   sad_lin  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示