ACM-五边形数定理 and 整数划分问题知识点总结

不是什么太重要或者常考的点,但是既然学了就记录下吧

五边形数

顾名思义,就是能组成五边形的数所组成的序列,具体看图。
序列中的第n个数为 f ( n ) = n ( 3 ∗ n − 1 ) 2 f(n)={n(3*n-1)\over 2} f(n)=2n(3n1)
在这里插入图片描述

转自维基百科

广义五边形数

就是将五边形数扩展到负数范围内。

n01-12–2-3–3
f(n)012571215

五边形数定理

下面是我们的正菜:五边形数定理
我们定义欧拉函数(这个欧拉函数和数论里的应该没有关系?):
ϕ ( x ) = ∏ i = 1 ∞ ( 1 − x i ) \phi(x)=\prod_{i=1}^{\infty}(1-x^i) ϕ(x)=i=1(1xi)
五边形数定理:
ϕ ( x ) = ∑ i = − ∞ i = ∞ ( − 1 ) i x i ( 3 i − 1 ) 2 = 1 + ∑ i = 1 ∞ ( − 1 ) i x i ( 3 i + 1 ) 2 \phi(x)=\sum_{i=-\infty}^{i=\infty}(-1)^ix^{i(3i-1)\over 2}=1+\sum_{i=1}^{\infty}(-1)^ix^{i(3i+1)\over 2} ϕ(x)=i=i=(1)ix2i(3i1)=1+i=1(1)ix2i(3i+1)
可以看到,x肩上的数就是五边形数
证明就不说了,可以参考其他大佬的博客

和整数划分问题

设P(n)为将n划分为多个可相等的正整数的方案。
写出P(n)的生成函数:
F ( x ) = ∏ i = 1 ∞ ( 1 + x i + x 2 i + x 3 i + … … ) = ∏ i = 1 ∞ ( 1 − x n i ) 1 − x i = ∏ i = 1 ∞ 1 1 − x i ( n − > ∞ ) F(x)=\prod_{i=1}^\infty (1+x^{i}+x^{2i}+x^{3i}+……)=\prod_{i=1}^\infty{(1-x^{ni})\over {1-x^i}}=\prod_{i=1}^\infty{1\over {1-x^i}}(n->\infty) F(x)=i=1(1+xi+x2i+x3i+)=i=11xi(1xni)=i=11xi1(n>)
而根据生成函数的定义:
F ( x ) = ∑ i = 1 ∞ P ( i ) x i F(x)=\sum_{i=1}^\infty P(i)x^i F(x)=i=1P(i)xi
我们发现F(x)和上面的 ϕ ( x ) \phi(x) ϕ(x)互为倒数:
F ( x ) ϕ ( x ) = 1 F(x)\phi(x)=1 F(x)ϕ(x)=1
暴力展开后会发现:
P ( n ) = P ( n − 1 ) + P ( n − 2 ) − P ( n − 5 ) − P ( n − 7 ) + … … P(n)=P(n-1)+P(n-2)-P(n-5)-P(n-7)+…… P(n)=P(n1)+P(n2)P(n5)P(n7)+
发现,P(n)可以由+/-P(n-五边形数)递推出
据此,可以以O(nsqrt(n))的复杂度预处理,O(1)处理询问解决整数划分问题。

例题

Partition HDU - 4651

板子题。就是求P(n)。根据上面的式子,我们打出五边形数,分别存下n为整数和负数的部分,然后,令f[0]=1后开始递推就行。

求P(n)和五边形数的板子:
ll f1[maxn],f2[maxn];
ll f[maxn];
void init(){
    for(int i=0;i<maxn;++i){
        f1[i]=1ll*i*(3*i+1)/2%mod;
        f2[i]=1ll*i*(3*i-1)/2%mod;
    }
    //预处理五边形数
    f[0]=1;
    for(int i=1;i<maxn;++i){
        int mx=0;
        for(int j=1;;++j){
            if(i>=f2[j]){//f2放前面,防止提前break
                if(j&1)f[i]=((f[i]+f[i-f2[j]])%mod+mod)%mod;
                else f[i]=((f[i]-f[i-f2[j]])%mod+mod)%mod;
            }
            else break;
            if(i>=f1[j]){
                if(j&1)f[i]=((f[i]+f[i-f1[j]])%mod+mod)%mod;
                else f[i]=(((f[i]-f[i-f1[j]]))%mod+mod)%mod;
            }
            else break;
        }
    }
}
AC代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1000000007;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){
	ll ans=1;
	while(n){
		if(n&1) ans=(ans*a)%mod;
		a=a*a%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
#define int ll
#define MOD(x) (((x%mod)+mod)%mod)
const int maxn=1e5+10;
ll f1[maxn],f2[maxn];
ll f[maxn];
void init(){
    for(int i=0;i<maxn;++i){
        f1[i]=1ll*i*(3*i+1)/2%mod;
        f2[i]=1ll*i*(3*i-1)/2%mod;
    }
    f[0]=1;
    for(int i=1;i<maxn;++i){
        int mx=0;
        for(int j=1;;++j){
            if(i>=f2[j]){
                if(j&1)f[i]=((f[i]+f[i-f2[j]])%mod+mod)%mod;
                else f[i]=((f[i]-f[i-f2[j]])%mod+mod)%mod;
            }
            else break;
            if(i>=f1[j]){
                if(j&1)f[i]=((f[i]+f[i-f1[j]])%mod+mod)%mod;
                else f[i]=(((f[i]-f[i-f1[j]]))%mod+mod)%mod;
            }
            else break;
        }
    }
}

signed main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//clock_t c1 = clock();
	//===========================================================
    init();
    int t;
    read(t);
    while(t--){
        int n;read(n);
        write(f[n]);putchar('\n');
    }
	//===========================================================
	//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
	return 0;
}

Integer Partition HDU - 4658

在上一题的基础上加上一个限制:每个数不超过k次。
我们依旧写出生成函数:
∏ i = 1 ∞ ( 1 + x i + x 2 i + x 3 i + … … + x ( k − 1 ) i ) = ∏ i = 1 ∞ ( 1 − ( x i ) k ) 1 − x i = ϕ ( x k ) ϕ ( x ) = ϕ ( x k ) F ( x ) \prod_{i=1}^\infty(1+x^i+x^{2i}+x^{3i}+……+x^{(k-1)i})=\prod_{i=1}^\infty{(1-(x^i)^{k})\over{1-x^i}}={\phi(x^k)\over \phi(x)}=\phi(x^k)F(x) i=1(1+xi+x2i+x3i++x(k1)i)=i=11xi(1(xi)k)=ϕ(x)ϕ(xk)=ϕ(xk)F(x)
分别将两个函数带入,暴力拆解后求得其第n项的系数:
F k ( n ) = P ( n ) − P ( n − k ) − P ( n − 2 k ) + P ( n − 5 k ) + P ( n − 7 k ) … … F_k(n)=P(n)-P(n-k)-P(n-2k)+P(n-5k)+P(n-7k)…… Fk(n)=P(n)P(nk)P(n2k)+P(n5k)+P(n7k)
带入就行了

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){
	ll ans=1;
	while(n){
		if(n&1) ans=(ans*a)%mod;
		a=a*a%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
#define int ll
const int maxn=1e5+10;
#define MOD(x) (((x)%mod+mod)%mod)
ll f1[maxn],f2[maxn],f[maxn];
ll n,k;
void init(){
    for(int i=0;i<maxn;++i){
        f1[i]=1ll*i*(3*i-1)/2;
        f2[i]=1ll*i*(3*i+1)/2;
    }
    f[0]=1;
    for(int i=1;i<maxn;++i){
        for(int j=0;;j++){
            if(i>=f1[j]){
                if(j&1)f[i]=MOD(f[i]+f[i-f1[j]]);
                else f[i]=MOD(f[i]-f[i-f1[j]]);
            }
            else break;
            if(i>=f2[j]){
                if(j&1)f[i]=MOD(f[i]+f[i-f2[j]]);
                else f[i]=MOD(f[i]-f[i-f2[j]]);
            }
        }
    }
}

ll solve(){
    ll ans=f[n];
    for(int i=1;;i++){
        if(n>=f1[i]*k){
            if(i&1)ans=MOD(ans-f[n-f1[i]*k]);
            else ans=MOD(ans+f[n-f1[i]*k]);
        }        
        else break;
        if(n>=f2[i]*k){
            if(i&1)ans=MOD(ans-f[n-f2[i]*k]);
            else ans=MOD(ans+f[n-f2[i]*k]);
        }else break;
    }
    return ans;
}

signed main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//clock_t c1 = clock();
	//===========================================================
    init();
    int t;read(t);
    while(t--){
        read(n);read(k);
        write(solve());putchar('\n');
    }
	//===========================================================
	//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值