题意:给出n, 求出把n写成若干个正整数的立方和的方案数,
例如21有3种写法, 21=1^3+1^3+...+1^3 = 2^3+1^3+....+1^3 = 2^3+2^3+1^3+...+1^3;
99有440 022 018 293种写法
思路:
一开始比较容易想到的是 dp[i][j]表示用不超过i的整数 的立方和 累加和为J的方案数;
以此为出发点,我们可以得到 dp[i+1][j+(i+1)^3]+=dp[i][j], 也就是在dp[i][j] 的每一个方案都加上一个 (i+1)^3 , 从而得到j+(i+1)^3 ,
当然dp[i][j] 还可以对 dp[i+1][j+2*(i+1)^3]有贡献,
还可以对 dp[i+1][j+3*(i+1)^3]有贡献,
还可以对 dp[i+1][j+4*(i+1)^3]有贡献,
.........
对 dp[i+1][j+k*(i+1)^3]有贡献。 (条件是j+k*(i+1)^3《10000)
那么我们就可以得到转移方程 三层循环
d[0][0] = 1; for(int i = 1; i <= 22; i++) //22^3>10000 for(int j = 0; j <= 10000; j++) for(int a = 0; j+a*i*i*i<=10000; a++) d[i][j+a*i*i*i] += d[i-1][j];
对其dp[ i ][ j ]分两种情况讨论,
情况1】 没有用上一个i
情况2】用了至少一个i
情况1显然就是 dp[i-1][j] ,一个i都没用而得到了J
对于情况2,我们可以看看dp[i][j]之前得到的答案有没有可以利用的。
可以发现dp[i][j-i^3] 表示用不超过i的整数 的立方和 累加和为J-i^3的方案数, 那么他里面用了多少个i我们是不知道的,但是我们可以知道的是,只要给dp[i][j-i^3] 的任一个方案,再加上一个i^3,就可以得到 一个 J,并且我们至少用上了一个i(我们自己加的),
所以 dp[i][j-i^3]的方案数,其实恰恰是 【 情况2】, 用了至少一个i的的dp[i][j]
............至此dp[i][j]就是两种情况叠加起来了
PS:有个细节是, 情况2下,至少用上一个I的前提是 J>=i^3(不然也没法用)
得到的转移方程是:
for(i=1;i<=21;i++) { for(j=0;j<=10000;j++) { if (j>=i*i*i) dp[i][j]=dp[i-1][j]+dp[i][j-i*i*i]; else dp[i][j]=dp[i-1][j]; } }
AC代码:o(n)
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; long long dp[30][10005]; int main() { dp[0][0]=1; long long i,j,k; for(i=1;i<=21;i++) { for(j=0;j<=10000;j++) { if (j>=i*i*i) dp[i][j]=dp[i-1][j]+dp[i][j-i*i*i]; else dp[i][j]=dp[i-1][j]; } } int n; while(scanf("%d",&n)!=EOF) printf("%lld\n",dp[21][n]); return 0; }
o(n^2)代码:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; long long dp[30][10005]; const long long MAX=500000000000; int main() { dp[0][0]=1; long long i,j,k; for(i=1;i<=21;i++) { for(j=0;j<=10000;j++) { for (k=0;j+k*i*i*i<=10000;k++) { dp[i][j+k*i*i*i]+=dp[i-1][j]; } } } int n; while(scanf("%d",&n)!=EOF) printf("%lld\n",dp[21][n]); return 0; }