把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1580 巧克力

题面传送门
对于这道题,明显可以\(dp\),将一张表预处理出来。
我们可以设\(f_{i,j,x,y,k}\)表示左下角为\(i,j\)右上角为\(x,y\),切大小为\(k\)的,转移时横竖各枚举切分点与\(k\)的分配转移,时间复杂度\(O(30^5\times 50^2)=O(1)\)
不过我们发现,实际上这道题任意大小一样的区间是没有区别的,也就是说任意\(f_{i,j,x,y,k}\)\(f_{i+s,j+s,x+s,y+s,k}\)是没有区别的,于是我们就可以将所有这种区间转化成\(f_{x-i,y-j,k}\)
那么思考一下这种区间怎么转移,仍旧枚举横竖区间,以竖区间为例,然后本来是转移\(f_{i-x,j,k-y}+f_{i-x+1i,j,y}\)的,但是这个区间可以映射到我们可以表示到的同一区间,就可以写出转移方程:\(f_{i,j,k}=min\{f_{i-x,j,k-y}+f_{x,j,y}+j^2\}\),横区间同样。
时间复杂度\(O(30^3\times 50^2)=6750000\),实际上还跑不满,再加上时限\(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]);
    }
}
posted @ 2020-03-28 13:57  275307894a  阅读(24)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end