这个题的本质是动态规划中的背包问题。
为什么会想到背包呢。
因为往往方案数不是排列组合就是递推或者是dp,当然还有其他的可能。我们可以把一个数的代价当成这个数的平方,价值就是一个方案数。由于这个数可以取无数次所以这个背包问题即为一个完全背包。 因此我们可以预处理出从1到数据范围的所有数的方案。
这个过程也是一个DP的过程。我们先把1到sqrt(数据范围)的数的平方数存到data数组中。然后再套用背包公式
因为最大的平方数是32768.所以最大的数是181.因此我们可以想象成共有181个物品。每个人所占的价值为data[i]。因为是四个二次方数。我们可设一个二维数组dp[i][j]表示数i在取j个平方数的时候的方案数。
因此我们可以得到状态转移方程。
for(int j=1;j<=181;j++)
for(int k=1;k<=32786;k++)
for(int i=1;i<=4;i++)
dp[当前的数][当前取平方数的个数]+=dp[当前的数-data[i]][当前取平方数的个数-1]
(dp[k][i]+=dp[k-data[i]][i-1];)
预处理完之后,这个题就结束了。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int t,data[182],sum,dp[35000][5]; int main() { dp[0][0]=1; for(int i=1;i<=181;i++) data[i]=i*i; for(int i=1;i<=181;i++) for(int j=data[i];j<=32768;j++) for(int k=1;k<=4;k++) { dp[j][k]+=dp[j-data[i]][k-1]; } scanf("%d",&t); while(t--) { int x,ans=0; scanf("%d",&x); for(int i=1;i<=4;i++) { ans+=dp[x][i]; } printf("%d ",ans); } }