题目链接:
https://www.luogu.com.cn/problem/P1586
#完全背包 #方案数 #二维背包 #Favorite
题意就是一个有限制的完全背包求方案数(注意审题,一开始我看成了 01 背包,调了二十分钟没调出来)
设 f[i][j][k]
表示为前
i
i
i 个物品,一维容量为
j
j
j,二维容量为
k
k
k 的背包方案数,对于每个物品,一维体积为
a
[
i
]
a[i]
a[i],二维体积为
1
1
1
这里有个细节需要考虑:
- 一维容量要求恰好装满
- 二维容量要求不超过
所以解决方法就是把状态定义为前 i i i 个物品恰好装满一维容量为 j j j,二维容量为 k k k 的背包的方案数,最后用一个 f o r for for 循环累加起来即可
可以在一开始处理时就把所有数字处理出来,询问时直接 f o r for for 循环求和即可
代码
import java.io.*;
import java.util.*;
import static java.lang.Math.*;
public class Main {
static int status;
static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static PrintWriter cout = new PrintWriter(bw);
static StreamTokenizer st = new StreamTokenizer(buf);
public static int nextInt() throws IOException {
status = st.nextToken();
return (int) st.nval;
}
static int n, m, t;
static int[] a;
static int[][] f;
static final int INF = 0x3f3f3f3f, MOD = (int) 1e9 + 7;
public static void main(String[] args) throws IOException {
t = nextInt();
a = new int[1010];
f = new int[32769][5];
for(int i=1;i<=32768/i;i++)
a[++m]=i*i;
f[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=a[i];j<=32768;j++)
for(int k=1;k<=4;k++)
f[j][k]+=f[j-a[i]][k-1];
}
while(t-- >0){
n = nextInt();
int ans=0;
for(int i=1;i<=4;i++)
ans+=f[n][i];
cout.println(ans);
}
cout.flush();
}// End of main
}