题面传送门
对于这道题,明显可以
d
p
dp
dp,将一张表预处理出来。
我们可以设
f
i
,
j
,
x
,
y
,
k
f_{i,j,x,y,k}
fi,j,x,y,k表示左下角为
i
,
j
i,j
i,j右上角为
x
,
y
x,y
x,y,切大小为
k
k
k的,转移时横竖各枚举切分点与
k
k
k的分配转移,时间复杂度
O
(
3
0
5
×
5
0
2
)
=
O
(
1
)
O(30^5\times 50^2)=O(1)
O(305×502)=O(1)
不过我们发现,实际上这道题任意大小一样的区间是没有区别的,也就是说任意
f
i
,
j
,
x
,
y
,
k
f_{i,j,x,y,k}
fi,j,x,y,k与
f
i
+
s
,
j
+
s
,
x
+
s
,
y
+
s
,
k
f_{i+s,j+s,x+s,y+s,k}
fi+s,j+s,x+s,y+s,k是没有区别的,于是我们就可以将所有这种区间转化成
f
x
−
i
,
y
−
j
,
k
f_{x-i,y-j,k}
fx−i,y−j,k。
那么思考一下这种区间怎么转移,仍旧枚举横竖区间,以竖区间为例,然后本来是转移
f
i
−
x
,
j
,
k
−
y
+
f
i
−
x
+
1
i
,
j
,
y
f_{i-x,j,k-y}+f_{i-x+1i,j,y}
fi−x,j,k−y+fi−x+1i,j,y的,但是这个区间可以映射到我们可以表示到的同一区间,就可以写出转移方程:
f
i
,
j
,
k
=
m
i
n
{
f
i
−
x
,
j
,
k
−
y
+
f
x
,
j
,
y
+
j
2
}
f_{i,j,k}=min\{f_{i-x,j,k-y}+f_{x,j,y}+j^2\}
fi,j,k=min{fi−x,j,k−y+fx,j,y+j2},横区间同样。
时间复杂度
O
(
3
0
3
×
5
0
2
)
=
6750000
O(30^3\times 50^2)=6750000
O(303×502)=6750000,实际上还跑不满,再加上时限
2
s
2s
2s,可以跑过本题。
代码实现:
#include<cstdio>
#include<cstring>
inline int min(int a,int b){return a<b?a:b;}
using namespace std;
int n,m,k,f[39][39][139],z,a,b,c;
int main() {
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
register int i,j,k,x,y;
memset(f,0x3f,sizeof(f));
for(i=1; i<=30; i++) {
for(j=1; j<=30; j++) {
f[i][j][i*j]=f[i][j][0]=0;
for(k=1; k<=min(50,i*j); k++) {
if(k!=i*j) {
f[i][j][k]=1e9;
for(x=1; x<i; x++) {
for(y=0; y<k; y++){
f[i][j][k]=min(f[x][j][y]+f[i-x][j][k-y]+j*j,f[i][j][k]);
//if(i==30&&j==29&&k==25) printf("%d %d %d %d %d\n",x,y,i-x,k-y,f[x][j][y]+f[i-x][j][k-y]+j*j);
}
}
for(x=1; x<j; x++) {
for(y=0; y<k; y++){
f[i][j][k]=min(f[i][x][y]+f[i][j-x][k-y]+i*i,f[i][j][k]);
// if(i==30&&j==29&&k==25) printf("%d %d %d %d %d\n",x,y,j-x,k-y,f[i][x][y]+f[i][j-x][k-y]+i*i);
}
}
}
}
}
}
//printf("%d\n",f[30][29][25]);
scanf("%d",&n);
while(n--) {
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",f[a][b][c]);
}
}