【p1091】洛谷p1586四方定理题解

这个题的本质是动态规划中的背包问题。

为什么会想到背包呢。

因为往往方案数不是排列组合就是递推或者是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\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/liuwenyao/p/9215083.html
今日推荐