P1586 四方定理
经典背包+数学
细看题目,会发现这道题如果没有“四方”的限制,那么题目会非常好做;
那么我们可以尝试,多开一个维度,即可成立定义:
\(f[i][j]\) 表示 数 \(i\) 由 \(j\) 个数构成,并且 \(1 <= j <= 4\)。
将状态得出后,可以总结性质了。
本题只有一个性质,就是:价值不变。
几乎所有情景题中,背包问题 在每一次询问中,都有不同的价值与体积,那么我们每遍历一次,就要重新算一次;
但是数字一直不变,所以可以先预处理。
并且 \(2^{15} = 32768\) ,配合 \(100\) 次询问,只能在 \(O(n^2)\) 算法之前,加一个小小的常数。
这个常数就是\(4\)。
那么先预处理一遍dp,每次询问将四种构成的集合相加,问题就迎刃而解。
时间复杂度:\(O( 4*( n^2 + T ) )\) 。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1<<15|1;
int f[N][5];
void init()
{
f[0][0]=1; // 0不需要任何数构成
for(int i=1;i*i<N;i++)
for(int j=i*i;j<N;j++)
for(int k=1;k<=4;k++)
f[j][k]+=f[j-i*i][k-1];
}
int main()
{
init();
int n; cin>>n;
while(n--)
{
int x; cin>>x;
int res=0;
for(int i=1;i<=4;i++) res+=f[x][i];
cout<<res<<endl;
}
return 0;
}
本文来自博客园,作者:{三季野花},转载请注明原文链接:https://www.cnblogs.com/SanGarden/articles/16631733.html