《洛谷P2140 小Z的电力管制》

这题做出来了很有成就感(骄傲.jpg)

虽然这题没评级,但我感觉应该有紫题难度吧?

Solution:

数据很小,然后题目里说了要横纵分解区域。

所以可以从这里出发,dfs分解区域。

具体怎么分解:可以发现,如果在这个地方分解开当前区域,那么必须满足两边断电后都能满足。

如果可以,那么再去看是否能分解到更小的即可。

做到这里之后,一交,T了。

显然,过于暴力了。

考虑记忆化搜素,设dp[x1][y1][x2][y2]表示区域(x1,y1)~(x2,y2)能分解成的最多区域数。

交了一发又T了,原来一开始我统计区域面积的时候是暴力求的。。显然可以前缀和O(1)求出。

嗯。AC。

注意:题目求的是最大的区域最小值。这里一定要判断清楚。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e4+5;
const int M = 2e4+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;
void FRE(){/*freopen("data1.in","r",stdin);
freopen("data1.out","w",stdout);*/}

int n,m,u,a[35][35],sum = 0,pre[35][35];
pii dp[35][35][35][35];
int cal(int x1,int y1,int x2,int y2)
{
    return pre[x2][y2]+pre[x1-1][y1-1]-pre[x1-1][y2]-pre[x2][y1-1];
}
pii dfs(int x1,int y1,int x2,int y2,int all)
{
    if(dp[x1][y1][x2][y2].first != 0) return dp[x1][y1][x2][y2];
    if(x1 == x2 && y1 == y2) return pii{1,u-(sum-all)};
    pii tmp;
    tmp.first = 1;
    tmp.second = u-(sum-all);
    for(int i = y1;i < y2;++i)//纵向划分
    {
        int cal1 = cal(x1,y1,x2,i);
        int cal2 = cal(x1,i+1,x2,y2);
        if(sum-cal1 <= u && sum-cal2 <= u)
        {
            pii ma1 = dfs(x1,y1,x2,i,cal1);
            pii ma2 = dfs(x1,i+1,x2,y2,cal2);
            if(ma1.first+ma2.first > tmp.first)
            {
                tmp.first = ma1.first+ma2.first;
                tmp.second = min(ma1.second,ma2.second);
            }
            else if(ma1.first+ma2.first == tmp.first) tmp.second = max(tmp.second,min(ma1.second,ma2.second));
        }
    }
    for(int i = x1;i < x2;++i)//横向划分
    {
        int cal1 = cal(x1,y1,i,y2);
        int cal2 = cal(i+1,y1,x2,y2);
        if(sum-cal1 <= u && sum-cal2 <= u)
        {
            pii ma1 = dfs(x1,y1,i,y2,cal1);
            pii ma2 = dfs(i+1,y1,x2,y2,cal2);
            if(ma1.first+ma2.first > tmp.first)
            {
                tmp.first = ma1.first+ma2.first;
                tmp.second = min(ma1.second,ma2.second);
            }
            else if(ma1.first+ma2.first == tmp.first) tmp.second = max(tmp.second,min(ma1.second,ma2.second));
        }
    }
    return dp[x1][y1][x2][y2] = tmp;
}
int main()
{
    n = read(),m = read(),u = read();
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j) a[i][j] = read(),sum += a[i][j];
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j) pre[i][j] = pre[i][j-1]+pre[i-1][j]-pre[i-1][j-1]+a[i][j];
    pii ans = dfs(1,1,n,m,sum);//左下,右上
    printf("%d %d\n",ans.first,ans.second);
  //  system("pause");    
}
View Code

 

posted @ 2020-09-14 07:09  levill  阅读(204)  评论(0编辑  收藏  举报