五边形数生成函数即欧拉函数:
推导
五边形数定理用来描述欧拉函数展开式的特性:
欧拉函数的倒数是划分数的生成函数:
由定义我们可以得到:
通过这个我们可以得到划分数的递推式。
同时发现五边形数生成函数的项数是 $O(\sqrt n)$ 级别的,故我们可以在 $O(n \sqrt n)$ 的时间复杂度内求出划分数前 $n$ 项。
我们也可以通过这种方法求有限制时的划分数:现在限制划分的每个数的大小小于 $k$,则有
则
在先求出划分数的生成函数之后,我们同样可以在 $O(\sqrt n)$ 的时间复杂度内求出 $F(x)$ 的单项。
例题
HDU4651
1 2 3 4 5 6 7 8 9
| #include<bits/stdc++.h> const int N=1e5+10,mod=1e9+7; int T,n,m,f[N],g[N]; int main(){ f[0]=1; for(int i=1;i*(3*i-1)/2<=100000;i++)g[m++]=i*(3*i-1)/2,g[m++]=i*(3*i+1)/2; for(int n=1;n<=100000;n++)for(int j=0;j<m&&g[j]<=n;j++)f[n]=(f[n]+(((j>>1)&1)?mod-1ll:1ll)*f[n-g[j]])%mod; for(scanf("%d",&T);T--;)scanf("%d",&n),printf("%d\n",f[n]); }
|
HDU4658
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<bits/stdc++.h> const int N=5e5+10,mod=1e9+7; int T,n,m,k,res,f[N],g[N]; int main(){ f[0]=1; for(int k=1;k*(3*k-1)/2<=100000;k++)g[m++]=k*(3*k-1)/2,g[m++]=k*(3*k+1)/2; for(int i=1;i<=100000;i++)for(int j=0;j<m&&g[j]<=i;j++)f[i]=(f[i]+f[i-g[j]]*((j>>1)&1?mod-1ll:1ll))%mod; for(scanf("%d",&T);T--;){ scanf("%d%d",&n,&k),res=f[n]; for(int i=0;i<m&&g[i]*k<=n;i++)res=(res+f[n-g[i]*k]*((i>>1)&1?1ll:mod-1ll))%mod; printf("%d\n",res); } }
|
证明
欧拉函数展开式的证明:https://blog.csdn.net/visit_world/article/details/52734860