码迷,mamicode.com
首页 > 其他好文 > 详细

sgu250:Constructive Plan(单调性乱搞)

时间:2015-06-04 10:01:42      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:
      给出一个n?m01矩阵,0表示不能放,1表示能放,在其中放入三个矩形,要求满足如下条件:
      1.每个矩形面积大于0
      2.这些矩形必须是一个联通块,矩形之间不能重叠。
      3.矩形的左边界在同一条线上。
      4.中间矩形的横向长度小于两边矩形的横向长度。
      求出最大的三个矩形的总面积,无解输出?1

分析:
      我是个蒟蒻,TAT,想了一个晚上+中午+n个课间才想出来怎么做…
      首先我们枚举左边界jO(n)
      然后我们枚举中间矩形的上下边界p,qO(n2)
      现在已经O(n3)了,然而解法也是O(n3)(有没有感觉很神奇...)
      首先我们得有一些必要的预处理:rmi,j(i,j)向右能到达的最远距离,minrj,p,q表示第j列以pq行为左边界的矩形向右能到达的最远距离。
      设上矩形的上边界为x,下矩形的下边界为y
      思考一下发现我们要考虑两种情况,一个是中间矩形的minrj,p,qminrj,x,p?1minrj,p,qminrj,q+1,y,另一个是<

      先考虑第二种情况,这种情况下我们不需要缩减中间矩形的横向长度。(另一种情况会被上下矩形压制得横向长度减小)
      我们先确定中间矩形的上边界p,随着下边界q的下移,minrj,p,q会呈非递增增长,下面矩形的minrj,q+1,y会呈非递减增长,这时我们下面矩形的下边界y的范围可以下移,此时我们要求的就是这个范围内的下面矩形的最大面积值,然而这个是可以预处理的,就是预处理maxdj,q+1,y表示以第j列为左边界且以q+1为上边界,下边界在[q+1,y]范围内的矩形面积最大值,则maxdj,q+1,y=max(maxdj,q+1,y,(y?q)minrj,q+1,y?1),这个预处理是O(n3)的,不虚啊,同样我们可以预处理出类似的上面矩形对应的maxuj,q+1,y,这样我们就可以在O(1)的时间内算出面积最大值,这样我们就解决了这个问题了。

      回过头来考虑第一种情况,因为我们被迫缩减中间矩形的横向长度,因此在确定x,y,p,q后,把中间矩形的宽度变小(即把p++q??),总面积会变大,这个可以自己想一下(很显然的...),由此我们很显然可以把中间矩形的宽度设为1时,肯定是面积最大的(此时的时间要从枚举第j列算起)
      我们枚举中间矩形的那一行p,再枚举这个矩形缩减后的长度为t,预处理上面矩形的长度大于t的最大矩形面积maxu2j,p?1,t,下面矩形的长度大于t的最大矩形面积maxd2j,p+1,t,这个预处理也是O(n3)的,不虚啊。

      总之就差不多了,头一次写这么多,也不知道讲没讲清…能不能看懂看造化了…

AC code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 189;

int n, m;
int g[MAXN][MAXN];
int rm[MAXN][MAXN];
int minr[MAXN][MAXN];

struct data
{
    int c, p1, p2, p3, p4, l1, l2, l3, s;
    data(int c=0, int p1=0, int p2=0, int p3=0, int p4=0, int l1=0, int l2=0, int l3=0, int s=0):c(c),p1(p1),p2(p2),p3(p3),p4(p4),l1(l1),l2(l2),l3(l3),s(s){}
}ans;

struct data2
{
    int p, l, s;
    data2(int p=0, int l=0, int s=0):p(p),l(l),s(s){}
    void init() {p = l = s = 0;}
};

data2 maxu[MAXN][MAXN];
data2 maxd[MAXN][MAXN];
data2 maxu2[MAXN][MAXN];
data2 maxd2[MAXN][MAXN];

void work_rm()
{
    for(int j = m; j >= 1; --j)
        for(int i = 1; i <= n; ++i)
            if(!g[i][j])
                rm[i][j] = rm[i][j+1]+1;
}

void work_minr(int j)
{
    for(int i = 1; i <= n; ++i)
    {
        minr[i][i] = rm[i][j];
        for(int k = i+1; k <= n; ++k)
            minr[i][k] = min(minr[i][k-1], rm[k][j]);
    }
}

void work_maxu()
{
    for(int i = 1; i <= n; ++i)
    {
        maxu[i][i] = data2(i, minr[i][i], minr[i][i]);
        for(int k = i-1; k >= 1; --k)
            if(maxu[i][k+1].s > (i-k+1)*minr[k][i])
                maxu[i][k] = maxu[i][k+1];
            else maxu[i][k] = data2(k, minr[k][i], (i-k+1)*minr[k][i]);
    }
}

void work_maxd()
{
    for(int i = n; i >= 1; --i)
    {
        maxd[i][i] = data2(i, minr[i][i], minr[i][i]);
        for(int k = i+1; k <= n; ++k)
            if(maxd[i][k-1].s > (k-i+1)*minr[i][k])
                maxd[i][k] = maxd[i][k-1];
            else maxd[i][k] = data2(k, minr[i][k], (k-i+1)*minr[i][k]);
    }
}

void work_maxu2()
{
    for(int i = 1; i <= n; ++i)
    {
        int u = i;
        for(int j = m; j >= 1; --j)
        {
            maxu2[i][j].init();
            u = min(i, u);
            while(u && minr[u][i] > j) u--;
            u++;if(u > i) continue;
            maxu2[i][j] = maxu[i][u];   
        }
    }
}

void work_maxd2()
{
    for(int i = n; i >= 1; --i)
    {
        int d = i;
        for(int j = m; j >= 1; --j)
        {
            maxd2[i][j].init();
            d = max(i, d);
            while(d <= n && minr[i][d] > j) d++;
            d--;if(d < i) continue;
            maxd2[i][j] = maxd[i][d];
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%d", &g[i][j]);
    work_rm();
    for(int j = 1; j <= m; ++j)
    {
        work_minr(j), work_maxu(), work_maxd();
        for(int p = 2; p <= n-1; ++p)
        {
            int u = p-1, d = p+1; 
            for(int q = p; q <= n-1 && minr[p][q]; ++q)
            {
                u = min(p-1, u), d = max(q+1, d);
                while(u && minr[u][p-1] > minr[p][q]) u--;u++;if(u >= p) continue;
                while(d <= n && minr[q+1][d] > minr[p][q]) d++;d--;if(d <= q) continue;
                if(ans.s < (q-p+1)*minr[p][q]+maxu[p-1][u].s+maxd[q+1][d].s)
                    ans = data(j, maxu[p-1][u].p, p, q+1, maxd[q+1][d].p, maxu[p-1][u].l, minr[p][q], maxd[q+1][d].l, (q-p+1)*minr[p][q]+maxu[p-1][u].s+maxd[q+1][d].s);
            }
        }
        work_maxu2(), work_maxd2();
        for(int p = 2; p <= n-1; ++p)
            if(minr[p][p] > 1)
                for(int q = 1; q < minr[p][p]; ++q)
                    if(maxu2[p-1][q].s && maxd2[p+1][q].s && ans.s < q+maxu2[p-1][q].s+maxd2[p+1][q].s)
                        ans = data(j, maxu2[p-1][q].p, p, p+1, maxd2[p+1][q].p, maxu2[p-1][q].l, q, maxd2[p+1][q].l, q+maxu2[p-1][q].s+maxd2[p+1][q].s);
    }
    for(int i = ans.p1; i < ans.p2; ++i)
        for(int j = 1; j <= ans.l1; ++j)
            g[i][ans.c+j-1] = 8;
    for(int i = ans.p2; i < ans.p3; ++i)
        for(int j = 1; j <= ans.l2; ++j)
            g[i][ans.c+j-1] = 8;
    for(int i = ans.p3; i <= ans.p4; ++i)
        for(int j = 1; j <= ans.l3; ++j)
            g[i][ans.c+j-1] = 8;
    if(ans.s)
    {
        printf("%d\n", ans.s);
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
                printf("%d", g[i][j]);
                if(j < m) printf(" ");  
            }
            puts("");
        }
    }
    else puts("-1");

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;   
}

sgu250:Constructive Plan(单调性乱搞)

标签:

原文地址:http://blog.csdn.net/qq_20118433/article/details/46351421

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!