一.将n划分为小于m的划分数
1 划分的多个整数可以存在相同的
dp[n][m] = dp[n][m-1]+dp[n-m][m]
(1) 如果划分中的每个数都小于m,相当于dp[n][m] = dp[n][m-1] ,就是说将n划分为小于m的划分数 等于 将n划分为小于m-1的划分数
(2)如果划分中的存在一个数等于m,相当于dp[n][m] = dp[n-m][m],就是将划分中的m减去 ,求n-m的划分数
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
const int maxn = 1000;
int dp[maxn][maxn];
int main(){
int n,m;
cin>>n>>m;
memset(dp,0,sizeof dp);
for(int i = 1;i <= n;i++){
dp[i][1]= i;
dp[1][i] = 1;
dp[0][i] = 1;
}
for(int i = 1;i <= n ;i++)
for(int j = 1; j <= n;j++){
if(j < i)
dp[i][j] = dp[i][j-1] + dp[i-j][j];
else if(j == i)
dp[i][j] = dp[i][j-1] + 1;
else
dp[i][j] = dp[i][j-1];
}
cout<<dp[n][m]<<endl;
return 0;
}
2.划分的多个整数不可以存在相同的
dp[n][m] = dp[n][m-1] + dp[n-m][m-1]
(1) 如果划分中的每个数都小于m,相当于dp[n][m] = dp[n][m-1] ,就是说将n划分为小于m的划分数 等于 将n划分为小于m-1的划分数
(2) 如果划分中的存在一个数等于m,相当于dp[n][m] = dp[n-m][m-1],因为这时候不能存在相同的,n减去m之后,就不会再存在等于m的划分,就是说所有的划分都小于m
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
const int maxn = 1000;
int dp[maxn][maxn];
int main(){
int n,m;
cin>>n>>m;
memset(dp,0,sizeof dp);
for(int i = 1;i <= n;i++){
dp[i][1]= i;
dp[1][i] = 1;
dp[0][i] = 1;
}
for(int i = 1;i <= n ;i++)
for(int j = 1; j <= n;j++){
if(j < i)
dp[i][j] = dp[i][j-1] + dp[i-j][j-1];
else if(j == i)
dp[i][j] = dp[i][j-1] + 1;
else
dp[i][j] = dp[i][j-1];
}
cout<<dp[n][m]<<endl;
return 0;
}
二.将n划分为k个正整数的划分数
dp[n][k] = dp[n-k][k] +dp[n-1][k-1]
(1) 如果划分的这k个正整数都是大于1的. dp[n][k] = dp[n-k][k] .就是将这k个正整数都减去1 ,它们的和就是m-k,就是相当于将n-k划分为k个正整数
(2)如果划分的这k个正整数有一个等于1的,dp[n][k] = dp[n-1][k-1] . 就是将这k个划分中的1减去 ,然后就相当于将n-1划分为k-1个正整数
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
const int maxn = 1000;
int dp[maxn][maxn];
int main(){
int n,m;
cin>>n>>m;
memset(dp,0,sizeof dp);
for(int i = 1;i <= n;i++)
dp[i][1]= 1;
for(int i = 1;i <= n ;i++)
for(int j = 1; j <= i;j++){
if(j < i)
dp[i][j] = dp[i-j][j] + dp[i-1][j-1];
else if(j == i)
dp[i][j] = 1;
}
cout<<dp[n][m]<<endl;
return 0;
}
三.将m划分为连续的正整数的划分数
例如 15的划分
15
7 ,8
4,5,6
1,2,3,4,5
将正整数m划分为连续的正整数,假设连续的最小值为x,划分的个数为i,那么 m = x*i + i*(i-1)/2
划分的个数最多 为 x从1开始取值 ,如果i 是整数 ,就可以确定 划分的个数最多是 i,如果i不是整数 ,说明划分的个数比 i小
所以最大的划分数满足 i +i*(i-1)/2 <=m, 然后就可以根据划分数 i 来求的连续的最小值x,如果x为整数 ,说明划分数为i,最小值为x 是m的一种划分
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int split(const int m){
int ans = 0;
for(int i = 1; i+i*(i-1)/2 <= m;i++ ){
int qt = m - i*(i-1)/2;
int qc = qt%i;
if(!qc){
int x = qt/i;char ch;
for(int j = 0;j < i;j++)
printf("%d%c",x+j,j==i-1? ch = '\n':ch = ' ');
ans++;
}
}
return ans;
}
int main(){
int m;
cin>>m;
cout<<split(m)<<endl;
return 0;
}