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

Partition

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 114    Accepted Submission(s): 46


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 ≤ 10 5) 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
 


 

Source
2013 Multi-University Training Contest 5
 


 

Recommend
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[n]);
     }
   }
    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[n]);
    }
    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[n][m]!=-1)return dp[n][m];
    LL ret=0;
    if (n < m)
        {ret=Part(n, n);
         ret%=mod;
         if(m<1000)dp[n][m]=ret;
         return ret;
        }
    if (n == m)
        {ret=Part(n, m-1) + 1;
         ret%=mod;
         if(m<1000)dp[n][m]=ret;
         return ret;
        }
        ret=Part(n, m-1) + Part(n-m, m);
        ret%=mod;
        if(m<1000)dp[n][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");
  }
}


 

 

你可能感兴趣的:(hdu 4671 Partition(DP,整数划分,5级))