不是什么太重要或者常考的点,但是既然学了就记录下吧
五边形数
顾名思义,就是能组成五边形的数所组成的序列,具体看图。
序列中的第n个数为
f
(
n
)
=
n
(
3
∗
n
−
1
)
2
f(n)={n(3*n-1)\over 2}
f(n)=2n(3∗n−1)
转自维基百科
广义五边形数
就是将五边形数扩展到负数范围内。
n | 0 | 1 | -1 | 2 | –2 | -3 | –3 |
---|---|---|---|---|---|---|---|
f(n) | 0 | 1 | 2 | 5 | 7 | 12 | 15 |
五边形数定理
下面是我们的正菜:五边形数定理
我们定义欧拉函数(这个欧拉函数和数论里的应该没有关系?):
ϕ
(
x
)
=
∏
i
=
1
∞
(
1
−
x
i
)
\phi(x)=\prod_{i=1}^{\infty}(1-x^i)
ϕ(x)=i=1∏∞(1−xi)
五边形数定理:
ϕ
(
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(3i−1)=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=1∏∞1−xi(1−xni)=i=1∏∞1−xi1(n−>∞)
而根据生成函数的定义:
F
(
x
)
=
∑
i
=
1
∞
P
(
i
)
x
i
F(x)=\sum_{i=1}^\infty P(i)x^i
F(x)=i=1∑∞P(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(n−1)+P(n−2)−P(n−5)−P(n−7)+……
发现,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(k−1)i)=i=1∏∞1−xi(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(n−k)−P(n−2k)+P(n−5k)+P(n−7k)……
带入就行了
#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;
}