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 @ 2024-09-08 18:20  sad_lin  阅读(21)  评论(0)    收藏  举报