bzoj3810 [Coci2015]Stanovi

传送门

题目

Input

输入一行,三个整数,n, m, k

Output

输出一个数,表示最小不满意度。

分析

我们要知道一个性质,即将一个符合条件的房间切成两个一定可以满足条件。所以我们用一个函数表示一个房间的长、宽以及它的四条边分别是否在最边下。所以我们枚举将一个房间切开的方向和每一块的大小,然后进行记忆化搜索即可。特别地,为了复杂度的优秀,我们可以将左边靠边而右边不靠边的房间转化为右边靠边而左边不靠边,这样我们可以将两种情况转化为一种,上边和下边的情况也像之前一样。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const long long inf=1e15+7;
long long k,f[305][305][2][2][2][2];
inline long long go(long long n,long long m,long long u,long long b,long long l,long long r){
      if(n<m){
        swap(n,m);
        swap(u,l);
        swap(b,r);
      }
      if(u<b)swap(u,b);
      if(l<r)swap(l,r);
      if(f[n][m][u][b][l][r]==-1){
          f[n][m][u][b][l][r]=(n*m-k)*(n*m-k);
          if(l||r||(u&&b)){
              for(long long i=1;i<n;i++)
                 f[n][m][u][b][l][r]=min(f[n][m][u][b][l][r],
                 go(i,m,u,0,l,r)+go(n-i,m,0,b,l,r));
          }
          if(u||b||(l&&r)){
              for(long long i=1;i<m;i++)
                 f[n][m][u][b][l][r]=min(f[n][m][u][b][l][r],
                 go(n,i,u,b,l,0)+go(n,m-i,u,b,0,r));
          }
      }
      return f[n][m][u][b][l][r];
}
int main()
{     long long n,m,i,j;
      memset(f,-1,sizeof(f));
      scanf("%lld%lld%lld",&n,&m,&k);
      printf("%lld
",go(n,m,1,1,1,1));
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9198216.html