五边形数定理

设第n个五边形数为,那么,即序列为:1, 5, 12, 22, 35, 51, 70, ...

 

对应图形如下:

 

 

设五边形数的生成函数为,那么有:

 

 

 

 

以上是五边形数的情况。下面是关于五边形数定理的内容:

 

五边形数定理是一个由欧拉发现的数学定理,描述欧拉函数展开式的特性。欧拉函数的展开式如下:

 

 

 

欧拉函数展开后,有些次方项被消去,只留下次方项为1, 2, 5, 7, 12, ...的项次,留下来的次方恰为广义五边形数。

 

 

五边形数和分割函数的关系

 

欧拉函数的倒数是分割函数的母函数,亦即:

 

   其中为k的分割函数。

 

上式配合五边形数定理,有:

 

 

 
在 n>0 时,等式右侧的系数均为0,比较等式二侧的系数,可得
 

p(n) - p(n-1) - p(n-2) + p(n-5) + p(n-7) + \cdots=0

 

因此可得到分割函数p(n)的递归式:p(n) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + \cdots

 

例如n=10时,有:p(10) = p(9) + p(8) - p(5) - p(3) = 30 + 22 - 7 -  3 = 42

 

 

所以,通过上面递归式,我们可以很快速地计算n的整数划分方案数p(n)了。

 

 

题目: http://acm.hdu.edu.cn/showproblem.php?pid=4651

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4.   
  5. using namespace std;  
  6. typedef long long LL;  
  7.   
  8. const int N=100005;  
  9. const LL MOD=1000000007;  
  10.   
  11. LL ans[N],tmp[N];  
  12.   
  13. void Init()  
  14. {  
  15.     int t=1000;  
  16.     for(int i=-1000;i<=1000;i++)  
  17.         tmp[i+t]=i*(3*i-1)/2;  
  18.     ans[0]=1;  
  19.     for(int i=1;i<N;i++)  
  20.     {  
  21.         ans[i]=0;  
  22.         for(int j=1;j<=i;j++)  
  23.         {  
  24.             if(tmp[j+t]<=i)  
  25.             {  
  26.                 if(j&1)  ans[i]+=ans[i-tmp[j+t]];  
  27.                 else     ans[i]-=ans[i-tmp[j+t]];  
  28.             }  
  29.             else break;  
  30.             ans[i]=(ans[i]%MOD+MOD)%MOD;  
  31.             if(tmp[t-j]<=i)  
  32.             {  
  33.                 if(j&1) ans[i]+=ans[i-tmp[t-j]];  
  34.                 else    ans[i]-=ans[i-tmp[t-j]];  
  35.             }  
  36.             else break;  
  37.         }  
  38.         ans[i]=(ans[i]%MOD+MOD)%MOD;  
  39.     }  
  40. }  
  41. int main()  
  42. {  
  43.     int t,n;  
  44.     Init();  
  45.     cin>>t;  
  46.     while(t--)  
  47.     {  
  48.         cin>>n;  
  49.         cout<<ans[n]<<endl;  
  50.     }  
  51.     return 0;  
  52. }  


 

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4658

 

题意:问一个数n能被拆分成多少种方法,且每一种方法里数字重复个数不能超过k(等于k)。
 
分析递推式为:
 
 
 
[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4.   
  5. using namespace std;  
  6. const int N = 100005;  
  7. const int MOD = 1000000007;  
  8.   
  9. int dp[N];  
  10.   
  11. void Init()  
  12. {  
  13.     dp[0] = 1;  
  14.     for(int i=1;i<N;i++)  
  15.     {  
  16.         dp[i] = 0;  
  17.         for(int j=1;;j++)  
  18.         {  
  19.             int t = (3*j-1)*j / 2;  
  20.             if(t > i) break;  
  21.             int tt = dp[i-t];  
  22.             if(t+j <= i) tt = (tt + dp[i-t-j])%MOD;  
  23.             if(j&1) dp[i] = (dp[i] + tt)%MOD;  
  24.             else    dp[i] = (dp[i] - tt + MOD)%MOD;  
  25.         }  
  26.     }  
  27. }  
  28.   
  29. int Work(int n,int k)  
  30. {  
  31.     int ans = dp[n];  
  32.     for(int i=1;;i++)  
  33.     {  
  34.         int t = k*i*(3*i-1) / 2;  
  35.         if(t > n) break;  
  36.         int tt = dp[n-t];  
  37.         if(t + i*k <= n) tt = (tt + dp[n-t-i*k])%MOD;  
  38.         if(i&1) ans = (ans - tt + MOD)%MOD;  
  39.         else    ans = (ans + tt)%MOD;  
  40.     }  
  41.     return ans;  
  42. }  
  43.   
  44. int main()  
  45. {  
  46.     Init();  
  47.     int n,k,t;  
  48.     scanf("%d",&t);  
  49.     while(t--)  
  50.     {  
  51.         scanf("%d%d",&n,&k);  
  52.         printf("%d\n",Work(n,k));  
  53.     }  
  54.     return 0;  
  55. }  

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值