Partition
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 117 Accepted Submission(s): 61
Problem Description
How many ways can the numbers 1 to 15 be added together to make 15? The technical term for what you are asking is the "number of partition" which is often called P(n). A partition of n is a collection of positive integers (not necessarily distinct) whose sum
equals n.
Now, I will give you a number n, and please tell me P(n) mod 1000000007.
Input
The first line contains a number T(1 ≤ T ≤ 100), which is the number of the case number. The next T lines, each line contains a number n(1 ≤ n ≤ 105) you need to consider.
Output
For each n, output P(n) in a single line.
Sample Input
4
5
11
15
19
Sample Output
7
56
176
490
五边形定理:(1-x)(1-x^2)(1-x^3)....(1-x^n) = 1-x-x^2+x^5+x^7-x^12-x^15+...,其中0,1,2,5,7,12,15..称之为广义五边形数。
其中(1-x)(1-x^2)..(1-x^n)为欧拉函数,欧拉函数的倒数是分割函数的母函数,既有(1-x)(1-x^2)...(1-x^n)*(1+p1*x+p2*x^2+..pn*x^n) = 1; 其中pk为k的分割函数。根据系数可以得到p(n)=p(n-1)+p(n-2)-p(n-5)-p(n-7)+p(n-12)+p(n-15)...比如p(10)*x^10+p(9)*x^9*(-x)+p(8)*x^8*(-x^2)+p(5)*x^5*(x^5)+p(3)*x^3*(x^7)=0,其中-x,-x^2,x^5,x^7中1,2,5,7便是广义五边形数。上式移项便得到递推公式p(n)=p(n-1)+p(n-2)-p(n-5)-p(n-7)+p(n-12)+p(n-15)-...
所以,首先将广义五边形数打表,广义五边形的通项公式为(3*n*n-n)/2,(3*n*n+n)/2。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 1000000007
using namespace std;
typedef long long LL;
LL pent[666],idx;
LL p[100010];
int main()
{
idx = 0;
for(LL i=1; i<=300; i++) //打表,广义五边形数
{
pent[++idx] = (3*i*i-i)/2;
pent[++idx] = (3*i*i+i)/2;
}
memset(p,0,sizeof(p));
p[0] = 1;
for(int i=1; i<=100000; i++) //把分割函数打表,即是答案
{
int tim = 0;
for(int j=1; j<=601; j++)
{
if(pent[j] > i)
break;
if(tim % 4 <= 1) //先加两次
{
p[i] = (p[i] + p[i-pent[j]])%mod;
tim ++;
}
else
{
p[i] = p[i] - p[i-pent[j]]; //后减两次,然后循环
if(p[i] < 0)
p[i] = p[i]%mod + mod;
tim ++;
}
}
}
int cas;
scanf("%d",&cas);
while(cas--)
{
LL tar;
scanf("%I64d",&tar);
printf("%I64d\n",p[tar]);
}
return 0;
}