【BZOJ3885】【Usaco2015 Jan】Cow Rectangles 某奇怪的最大子矩形

广告:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44095063");
}

题意:

坐标系上给出n个点,分”H”和”G”,一个整点坐标上至多一个点。

现在求一个不包含”G”的包含尽量多”H”的子矩形,然后在保证”H”最多的情况下还要问最小面积。

输出”H”的最大数量,和保证”H”最多时的最小矩形面积。

题解:

我们发现因为坐标有限制[0,1000] (注意有”0”!!!),所以它是一个矩形。

第一问:

首先我们可以参照极大子矩形的做法算出所有的极大子矩形,然后维护一个fi,j表示[1,i][1,j]这个矩形内有多少”H”点,对于一个矩形O(1)时间就可以算出”H”个数。

第二问:

之后我们可以把每个极大子矩形多余的边角砍掉来算面积。

我们可以进行二分,看四个方向都能砍多少,check判的是矩形内”H”的个数是否为0。

当然,左右其实可以均摊O(1)算出来,诶我现在才发现都已经加了logn了,左右消减还写什么O(1)啊,噗Qwq。

那就不说了,想知道的自己去看代码吧。

还有就是下面不需要削。

不写了不写了,不懂的留言吧。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1010
#define inf 0x3f3f3f3f
using namespace std;
int map[N][N],f[N][N];
struct Data
{
    int H,h; // 最高距离、最近白点
    int l,r; // 左右有效距离
}s[N];
int ansa,ansb=inf;
int q[N];
inline int getans(int a,int b,int c,int d){return f[d][b]-f[d][a]-f[c][b]+f[c][a];}
inline int getarea(int a,int b,int c,int d)
{
    int l=c,r=d,mid,ans;
    while(l<=r)
    {
        if(r-l<=3)
        {
            ans=l;
            for(int i=r;i>=l;i--)
                if(getans(a,b,c,i)==0)
                    {ans=i;break;}
            break;
        }
        mid=l+r>>1;
        if(getans(a,b,c,mid)==0)l=mid;
        else r=mid-1;
    }
    return (b-a-1)*(d-ans-1);
}
int main()
{
    int i,j,k;
    int a,b,c;
    scanf("%d",&c);
    char ss[5];
    while(c--)
    {
        scanf("%d%d%s",&a,&b,ss),a++,b++;
        if(ss[0]==‘H‘)map[a][b]=1; // 可
        else map[a][b]=2; // 否
    }
    for(i=1;i<=1001;i++)
    {
        int temp=0;
        for(j=1;j<=1001;j++)
        {
            if(map[i][j]==1)temp++;
            f[i][j]=f[i-1][j]+temp;
        }
    }
    for(i=1;i<=1001;i++)s[i].h=inf;
    int l,r;
    for(i=1;i<=1001;i++)
    {
        for(j=1;j<=1001;j++)
        {
            if(map[i][j]==2)s[j].H=0,s[j].h=inf;
            else {
                s[j].H++;
                if(map[i][j]==1)s[j].h=1;
                else s[j].h++;
            }
            s[j].l=s[j].r=j;
        }
        l=1,r=0;
        for(j=1;j<=1001;j++)
        {
            while(l<=r&&s[q[r]].H>=s[j].H)s[j].l=s[q[r--]].l;
            while(s[j].l<j&&s[s[j].l].h>s[j].H)s[j].l++;
            q[++r]=j;
        }
        l=1,r=0;
        for(j=1001;j;j--)
        {
            while(l<=r&&s[q[r]].H>=s[j].H)s[j].r=s[q[r--]].r;
            while(s[j].r>j&&s[s[j].r].h>s[j].H)s[j].r--;
            q[++r]=j;
        }
        for(j=1;j<=1001;j++)
        {
            int ret=getans(s[j].l-1,s[j].r,i-s[j].H,i);
            if(ret>=ansa)
            {
                int temp=getarea(s[j].l-1,s[j].r,i-s[j].H,i);
                if(ret==ansa)ansb=min(ansb,temp);
                else ansa=ret,ansb=temp;
            }
        }
    }
    printf("%d\n%d\n",ansa,ansb);
    return 0;
}
时间: 2024-10-24 13:03:57

【BZOJ3885】【Usaco2015 Jan】Cow Rectangles 某奇怪的最大子矩形的相关文章

BZOJ 3887[Usaco2015 Jan]Grass Cownoisseur

题面: 3887: [Usaco2015 Jan]Grass Cownoisseur Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 237  Solved: 130[Submit][Status][Discuss] Description In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-way cow pat

bzoj3887: [Usaco2015 Jan]Grass Cownoisseur

题意: 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) =>有向图我们先考虑缩点.然后观察缩点后的图可以发现新的路径中必定只有一条边是反向的才符合条件.那么我们可以联想到某道最短路的题将边反向存一遍后分别从s和t跑一跑.那么这里bfs跑一跑就行了.然后有一个坑点:这种重建图的注意es和edges不然es会在中途就被修改掉了... #include<cstdio> #

线段树 BZOJ3888 [Usaco2015 Jan]Stampede

3888: [Usaco2015 Jan]Stampede Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 253  Solved: 81[Submit][Status][Discuss] Description Farmer John's N cows (1 <= N <= 50,000) appear to be stampeding along the road at the front of FJ's farm, but they are

bzoj3048[Usaco2013 Jan]Cow Lineup*

bzoj3048[Usaco2013 Jan]Cow Lineup 题意: 给你一个序列,你最多可以删去k类数(数列中相同的数字被称为一类数).求通过删数得到的该序列中的最长完美序列(满足所有的数字相等的连续子序列被叫做完美序列).序列大小≤100000 题解: 先离散化,然后维护一个单调队列,如果当前类数小于等于k+1就比较答案,否则左端点++. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorit

3890: [Usaco2015 Jan]Meeting Time( dp )

简单的拓扑图dp.. A(i, j), B(i, j) 表示从点 i 长度为 j 的两种路径是否存在. 用bitset就行了 时间复杂度O(m) ---------------------------------------------------------------- #include<bits/stdc++.h> #define clr(x, c) memset(x, c, sizeof(x)) #define rep(i, n) for(int i = 0; i < n; ++

bzoj3886: [Usaco2015 Jan]Moovie Mooving

题意: PoPoQQQ要在电影院里呆L分钟,这段时间他要看小型电影度过.电影一共N部,每部都播放于若干段可能重叠的区间,PoPoQQQ决不会看同一部电影两次.现在问他要看最少几部电影才能度过这段时间? 注:必须看电影才能在电影院里呆着,同时一场电影可以在其播放区间内任意时间入场出场.N=20.每部电影的重复区间<=100. =>N=20.那么我们还是考虑二进制枚举.转移方程类似.时间复杂度类似.哎呀套路啊... #include<cstdio> #include<cstrin

Cow Rectangles

Cow Rectangles 题目描述 The locations of Farmer John's N cows (1 <= N <= 500) are described by distinct points in the 2D plane.  The cows belong to two different breeds: Holsteins and Guernseys.  Farmer John wants to build a rectangular fence with sides

【BZOJ3889】【Usaco2015 Jan】Cow Routing 双键值最短路

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44064091"); } 题意: 从样例讲起. 第一行 s,t,m表示:起点,终点,m条航线. 然后m组,每组第一行len,n表示这条航线的代价, 这类似于公交车,只要用了就花这些钱,但是用多少都这些钱. 注意是单向边. 举例: 23

[bzoj1612][Usaco2008 Jan]Cow Contest奶牛的比赛_dfs

Cow Contest奶牛的比赛 bzoj-1612 Usaco-2008 Jan 题目大意:题目链接. 注释:略. 想法: 我们对于每个点dfs,看一下比这个点大的点加上比这个点小的点是否是n-1即可. 最后,附上丑陋的代码... ... #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N