Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 114 Accepted Submission(s): 46
4 5 11 15 19
7 56 176 490
根本就不会嘛公式谁会推啊,写个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"); } }