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;
}

posted @ 2022-08-27 22:53  Sankano  阅读(45)  评论(0编辑  收藏  举报