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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」