您的位置:首页 > 其它

hdu 4671 Partition(DP,整数划分,5级)

2013-08-06 19:57 363 查看

Partition

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 114 Accepted Submission(s): 46



[align=left]Problem Description[/align]
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.

[align=left]Input[/align]
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.

[align=left]Output[/align]
For each n, output P(n) in a single line.

[align=left]Sample Input[/align]

4
5
11
15
19


[align=left]Sample Output[/align]

7
56
176
490


[align=left]Source[/align]
2013 Multi-University Training Contest 5

[align=left]Recommend[/align]
zhuyuanchen520

根本就不会嘛公式谁会推啊,写个DP超,果断搜公式爆搜,终于找到了维基百科的公式了,结果题解给的就是这个网站。哎!这就一公式。

http://en.wikipedia.org/wiki/Partition_(number_theory)



#include<iostream>
#include<cstring>
#include<cstdio>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define clr(f,z) memset(f,z,sizeof(f))
#define LL __int64
using namespace std;
const int mm=1e5+9;
const LL mod=1000000007;
LL dp[mm],f[mm];
void getdata()
{ int zt=1000;
FOR(i,-1000,1000)f[i+zt]=i*(3*i-1)/2;
dp[0]=1;
FOR(i,1,mm-1)
{
dp[i]=0;
FOR(j,1,i)
{
if(f[j+zt]<=i)
{
if(j&1)
{
dp[i]+=dp[i-f[j+zt]];
}
else dp[i]-=dp[i-f[j+zt]];
}
else break;
dp[i]=(dp[i]%mod+mod)%mod;
if(f[zt-j]<=i)
{
if(j&1)
{
dp[i]+=dp[i-f[zt-j]];
}
else dp[i]-=dp[i-f[zt-j]];
}
else break;
}
dp[i]=(dp[i]%mod+mod)%mod;
}
}
int main()
{
int cas;
getdata();int n;
while(~scanf("%d",&cas))
{
while(cas--)
{
scanf("%d",&n);
printf("%I64d\n",dp
);
}
}
return 0;
}


背包版本

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<iostream>

using namespace std;

int a[100001];
int main()
{
//freopen("data.txt","w",stdout);
int lim = 10000;
a[0] = 1;
for(int i=1;i<=lim;i++)
for(int j=0;j+i<=lim;j++){
a[i+j] = (a[i+j] + a[j]);
if (a[i+j] >= 1000000007)
a[i+j] -= 1000000007;
}
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",a
);
}
return 0;
}


递归版本

#include<iostream>
#include<cstring>
#include<cstdio>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define clr(f,z) memset(f,z,sizeof(f))
#define LL __int64
using namespace std;
const int mm=1e5+9;
const LL mod=1000000007;
const int cd=1000;
LL dp[mm][cd];
LL Part(LL n,LL m)
{
if ((n < 1)||(m < 1))
return 0;
if ((n == 1)||(m == 1))
return 1;
if(m<1000&&dp
[m]!=-1)return dp
[m];
LL ret=0;
if (n < m)
{ret=Part(n, n);
ret%=mod;
if(m<1000)dp
[m]=ret;
return ret;
}
if (n == m)
{ret=Part(n, m-1) + 1;
ret%=mod;
if(m<1000)dp
[m]=ret;
return ret;
}
ret=Part(n, m-1) + Part(n-m, m);
ret%=mod;
if(m<1000)dp
[m]=ret;
return ret;
}

int main()
{
int cas,n;
clr(dp,-1);
while(~scanf("%d",&cas))
{
while(cas--)
{ //scanf("%d",&n);
FOR(i,1,50)
{ n=i;
printf("%d %I64d\n",i,Part(n,n));
}
}
}
return 0;
}


整数划分,求每个划分。

void print_partition(int n)
{
int i = 1;
int m = 1;
int h = 1;
int t, r;
int a[n + 1];

for (; i < n + 1; ++i) a[i] = 1;
a[1] = n;
printf("%d \n", a[1]);

while (a[1] != 1)
{
if (a[h] == 2)
{
a[h--]--;
m++;
}
else
{
r = --a[h];
t = m - h + 1;

while (t >= r)
{
a[++h] = r;
t -= r;
}
if (t == 0) m = h;
else m = h + 1;
if (t >= 2) a[++h] = t;
}
for (i = 1; i < m + 1; i++)
printf("%d ", a[i]);
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: