轉載自:http://blog.csdn.net/zhoufenqin/article/details/9821617
分拆數
在將分拆數之前先介紹一點五邊形數
http://en.wikipedia.org/wiki/Pentagonal_number
第n個五邊形數公式:p(n)=(3*n^2-n)/2
前幾個五邊形數:1, 5, 12, 22, 35, 51, 70, 92, 117, 145, 176, 210, 247, 287, 330, 376, 425, 477, 532, 590, 651, 715, 782, 852, 925, 1001 .........
2. 廣義五邊形數:
n的取值0,1,-1,2,-2,3,-3.......
前幾個廣義五邊形數:0, 1, 2, 5, 7, 12, 15, 22, 26, 35, 40, 51, 57, 70, 77, 92, 100, 117, 126, 145, 155, 176, 187, 210, 222, 247, 260, 287, 301, 330......
3. 中心五邊形數:
4.中心六邊形數
中心六邊形數跟廣義五邊形數有較大的關係,見圖
(相鄰兩個廣義五邊形數之和)
5. 五邊形數測試
利用以下的公式可以測試一個正整數x是否是五邊形數(此處不考慮廣義五邊形數):
若n是自然數,則x是五邊形數,而且恰爲第n個五邊形數。
若n不是自然數,則x不是五邊形數。
進入正題:分拆數
將一個數用一個或多個正整數的無序和來表示
例如4的分拆有5種:4 , 3+1 , 2+2 , 2+1+1 , 1+1+1+1
1. 限制分拆
給一些分拆加限制條件。例如8的分拆有22種,
其中分拆的數中全部都是奇數的有6種:7+1, 5+3, 5+1+1+1, 3+3+1+1, 3+1+1+1+1+1, 1+1+1+1+1+1+1+1;
同樣,若要求8分拆的數中是兩兩不同的也有6種:8, 7+1, 6+2, 5+3, 5+2+1, 4+3+1
已證明一個數的分拆中滿足以上兩種條件的個數是相同的,詳見http://en.wikipedia.org/wiki/Glaisher%27s_theorem
一些有關限制分拆的結論:
·n的分拆數中最大部分爲m的個數=把n分拆成m部分的個數
如圖,左邊最大部分m=3,等於把n拆成3部分(右圖) 把圖轉置即可
·n的分拆數中每一部分都小於等於m的個數=把n分成m份或更小
·n的分拆數中每部分的數都相等的個數=n 的因子個數
Eg. 6=2+2+2, 6=3+3,6=1+1+1+1+1+1
·n的分拆數中每部分都是1或2(或者把n分拆成1或2部分)的個數=floor(n/2+1);
Eg. 6=1+1+1+1+1+1, 6=1+1+1+1+2, 6=1+1+2+2, 6=2+2+2
·n的分拆數中每部分都是1或2或3(或者把n分拆成1或2或3部分)的個數=(n+3)^2/12;
2. 生成函數
因爲 ,右邊的表達式等於乘積(母函數)
Pn 等於方程n=a1+2*a2+3*a3+...+n*an 的非負整數解a1,a2...an 的個數。
若是用母函數的方法去做,n很大不容易解出來,繼續往下看
定義P(k,n)爲:將n表示成>=k 的數之和。Eg P(3,6): 6=3+3
1) 當最小的數爲k時,p(k,n) = p(k,n-k)。即在n-k表示成>=k的數之和的情況下再加入一個k,情況還是不變
2) 當最小的數>k時,則至少最小的數爲k+1,p(k,n)=p(k+1,n);
所以p(k,n)=p(k,n-k)+p(k+1,n)。k>n 時,p(k,n)=0,p(n,n)=1;
eg: p(9)=p(1,8)+p(2,7)+p(3,6)+p(4,5);
得到下表:
K n |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
... |
1 |
1 |
|
|
|
|
|
|
|
2 |
2 |
1 |
|
|
|
|
|
|
3 |
3 |
1 |
1 |
|
|
|
|
|
4 |
5 |
2 |
1 |
1 |
|
|
|
|
5 |
7 |
2 |
1 |
1 |
1 |
|
|
|
6 |
11 |
4 |
2 |
1 |
1 |
1 |
|
|
7 |
15 |
4 |
2 |
1 |
1 |
1 |
1 |
|
... |
|
|
|
|
|
|
|
|
前幾個分拆數1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42 ,56,77,101,135......
如果是按p(k,n)=p(k+1,n)+p(k,n-k) 來算,複雜度仍是0(n^2),往下看
右邊的分母是歐拉函數,可寫成
可以發現等式右邊x的指數爲擴展五邊形數,可根據之前介紹的擴展五邊形公式算得p(n)=(3*n^2-n)/2,係數符號爲(-1)^(m+1)
於是 p(k) = p(k − 1) + p(k − 2) − p(k − 5) − p(k − 7) + p(k − 12) + p(k − 15) − p(k − 22) − ...
Eg p(10)=p(9)+p(8)-p(5)-p(3)。複雜度降低了
/*
總結:
五邊形數:0, 1, 2, 5, 7, 12, 15, 22, 26, 35....
對應下標:0, 1, -1, 2, -2, 3, -3, 4, -4 , 5.....
所以 可以在O(N^1.5)的時間內求出p(1),p(2),...p(n)。
*/
Hdu 4658 要求拆分的數中每個數出現的次數不能大於等於k次,則
所以將8拆分的數中每個數的個數小於4的有16個,分別爲
8,1+7,1+1+6,1+1+1+5,6+2,1+5+2,1+1+4+2,1+1+1+3+2,4+2+2,1+3+2+2,1+1+2+2+2,1+1+3+3,1+4+3,5+3,2+3+3,4+4
hdu 4651
#include <cstdio>
#include <cstring>
#include<algorithm>
#define LL long long
const int mod=1000000000+7;
LL a[111111],f[111111];
int main()
{
int n,i,j,t;
a[0]=0;
LL sum;
for(i=1,j=1;i<500;i++)
{
a[j++]=(3*i*i-i)/2;
a[j++]=(3*i*i+i)/2;
}
int flag;
f[0]=1;
for(i=1;i<=100000;i++)
{
for(j=1,flag=1;a[j]<=i;j++)
{
if(j%4==1||j%4==2)flag=1;
else flag=-1;
f[i]=f[i]+flag*f[i-a[j]];
}
f[i]=(f[i]%mod+mod)%mod;
}
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%I64d\n",f[n]);
}
return 0;
}
hdu4658
#include <cstdio>
#include <cstring>
#include<algorithm>
#define LL long long
const int mod=1000000000+7;
LL a[111111],f[111111];
LL powmod(LL a)
{
int p=mod-2;
LL ans=1;
while(p)
{
if(p&1)ans=ans*a%mod;
a=a*a%mod;
p>>=1;
}
return ans;
}
int main()
{
int n,i,j,t,k;
a[0]=0;
LL sum;
for(i=1,j=1;i<500;i++)
{
a[j++]=(3*i*i-i)/2;
a[j++]=(3*i*i+i)/2;
}
int flag;
f[0]=1;
for(i=1;i<=100000;i++)
{
for(j=1,flag=1;a[j]<=i;j++)
{
if(j%4==1||j%4==2)flag=1;
else flag=-1;
f[i]=f[i]+flag*f[i-a[j]];
}
f[i]=(f[i]%mod+mod)%mod;
}
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
LL ans=f[n];
for(j=1,flag=1;a[j]*k<=n;j++)
{
if(j%4==1||j%4==2)flag=-1;
else flag=1;
ans+=flag*f[n-a[j]*k];
}
ans=(ans%mod+mod)%mod;
printf("%I64d\n",ans);
}
return 0;
}