母函数 整数拆分 ( hdu 1028 , poj 1221 )
介绍母函数的博文
hdu1028 这道题是母函数的基本题目
题目链接
题意:整数拆分,例如4的情况
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
限制:1 <= n <= 120
poj1221 这道题有助于加深对母函数的理解
题目链接
题意:
整数拆分,对称拆分
例如:
4: (4), (1 2 1), (2 2), (1 1 1 1)
对于一个整数n,求拆分的种类数。
限制:
0 <= n < 250
思路:
母函数
G[x]=(1+x+x^2+...)*(1+x^2+x^4+...)*(1+x^3+x^6+...)*...*(1+x^m+x^(2*m)+...)
/*poj1221
题意:
整数拆分,对称拆分
例如:4: (4), (1 2 1), (2 2), (1 1 1 1)
对于一个整数n,求拆分的种类数。
限制:
0 <= n < 250
思路:
母函数
G[x]=(1+x+x^2+...)*(1+x^2+x^4+...)*(1+x^3+x^6+...)*...*(1+x^m+x^(2*m)+...)
*/
#include
#include
using namespace std;
#define LL __int64
const int N=250;
LL c1[N],c2[N];
//G[x]=(1+x+x^2+...)*(1+x^2+x^4+...)*(1+x^3+x^6+...)*...*(1+x^m+x^(2*m)+...)
LL mhs(int n,int m){
for(int i=0;i<=n;++i) //第一个表达式
c1[i]=1,c2[i]=0;
for(int i=2;i<=m;++i){ //第i个表达式
for(int j=0;j<=n;++j) //第i个表达式的第j项
for(int k=0;k+j<=n;k+=i) //转移
c2[j+k]+=c1[j];
for(int j=0;j<=n;++j)
c1[j]=c2[j],c2[j]=0;
}
return c1[n];
}
int n;
void gao(){
LL ans=0;
if(n&1){
for(int i=1;i<=n;i+=2)
ans+=mhs((n-i)/2,i);
}
else{
ans=mhs(n/2,n);
for(int i=2;i<=n;i+=2)
ans+=mhs((n-i)/2,i);
}
printf("%d %I64d\n",n,ans);
}
int main(){
while(scanf("%d",&n) && n){
gao();
}
return 0;
}
当然由于上面的两道题目数据规模比较小,可以用dp来解决,而且效率更快。
对于数据规模较大(1e5级别)的整数拆分,要用到五边形数定理,在接下来的一篇文章里面会提到。
上面两道题的dp解法:
hdu1028
/*hdu1028
题意:整数拆分,例如4的情况
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
限制:1 <= n <= 120
思路:dp
dp[i][j]表示数字i,拆成以j为结尾的方式有多少种
*/
#include
#include
using namespace std;
#define LL __int64
LL dp[205][205];
LL ans[205];
int main(){
dp[1][1]=1;
for(int i=2;i<=120;++i){
for(int j=1;j<=i;++j){
for(int k=j;k<=i-j;++k){
dp[i][j]+=dp[i-j][k];
}
}
dp[i][i]=1;
}
for(int i=1;i<=120;++i)
for(int j=1;j<=i;++j)
ans[i]+=dp[i][j];
int n;
while(scanf("%d",&n)!=EOF){
printf("%I64d\n",ans[n]);
}
return 0;
}
poj 1221
/*poj1221
题意:
整数拆分,对称拆分
例如:4: (4), (1 2 1), (2 2), (1 1 1 1)
对于一个整数n,求拆分的种类数。
限制:
0 <= n < 250
思路:
由于数据较小,可以考虑 n^2 乃至 n^3 的dp
令dp[i][j]表示拆分整数 i 时,最大的数小于 j 的方法有多少种。
不难得出:
dp[i][j]=dp[i][j-1] + dp[i-j][min(j,i-j)];
一个 n^2 的dp。
*/
#include
#include
using namespace std;
#define LL __int64
const int N=250;
LL dp[N][N];
void predo(){
dp[0][0]=dp[1][1]=1;
for(int i=2;i