• ICPC2018焦作 J. Carpets Removal


    题意:

    m*m的网格上覆盖了n个长方形

    问拿走2个多少个长方形之后,最少有多少个格子没有被长方形覆盖

    解决两个问题

    1、如何知道每个格子被几个长方形覆盖

    2、如何知道被1和2个长方形覆盖的格子是被哪个长方形覆盖(被>=3个长方覆盖的格子没有贡献)

    如何知道每个格子被几个长方形覆盖?

    二维差分前缀和即可,设差分前缀和数组为cnt[i][j]

    如何知道被1个长方形覆盖的格子是被哪个长方形覆盖?

    对每个格子,用sum[i][j]记录盖在这个格子上的长方形的编号之和

    对于cnt[i][j]=1的格子(i,j),sum[i][j]即是覆盖它的长方形编号

    如何知道被2个长方形覆盖的格子是被哪2个长方形覆盖?

    即已知x+y=sum[i][j],再加什么信息可以唯一的确定一组x和y

    可以记录编号的平方和

    即pow2[i][j]表示记录盖在这个格子上的长方形的编号的平方和

    x+y=sum

    x*x+y*y=pow2

    求x,y

    ∵(x+y)*(x+y)=x*x+y*y+2*x*y=sum*sum

    ∴2*x*y=sum*sum-pow2

    ∴(x-y)*(x-y)=x*x+y*y-2*x*y=2*pow2-sum*sum

    ∴x-y=sqrt(2*pow2-sum*sum)

    ∴x=(sum+sqrt(2*pow2-sum*sum) )/2

    ∴y=sum-x

    如何去除长方形,能够新增最多的不被覆盖的格子?

    我们有两种去除长方形的方案

    方案1:选择两个只被一个长方形盖住的格子,去掉对应的长方形

    利用sum数组,对每个cnt=1的格子统计一下,即可算出每个长方形覆盖的且只被这个长方形覆盖的格子数量

    方案2:选择一个被两个长方形盖住的格子,去掉对应的长方形

    对每个cnt=2的格子,算出它对应的两个长方形,然后排序,满足排完序后对应一样的长方形排在一起即可

    假设是a 和 b

    那就是只被a覆盖的长方形+只被b覆盖的长方形+对应是a和b的格子数量

    答案就是所有的格子数量-初始没有被长方形覆盖的格子数量-上面两种方案的 最大值

    #include<cmath> 
    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    #define N 1502
    #define M 300001
    
    typedef long long LL;
    
    int cnt[N][N];
    LL sum[N][N],pow2[N][N];
    
    int s1[M];
    struct node
    {
        int a,b;
    }s2[N*N];
    
    bool cmp(node p,node q)
    {
        if(p.a!=q.a) return p.a<q.a;
        return p.b<q.b;
    }
    
    int main()
    {
    //    freopen("data.txt","r",stdin);
    //    freopen("my.txt","w",stdout);
        int T,n,m;
        int xl,xr,yu,yd;
        int s0,n3;
        int k1,k2;
        int ans,tmp,last,now;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=0;i<=m;++i)
                for(int j=0;j<=m;++j)
                    cnt[i][j]=sum[i][j]=pow2[i][j]=0;
            for(int i=1;i<=n;++i)
            {
                scanf("%d%d%d%d",&yu,&yd,&xl,&xr);
                ++cnt[yu][xl];
                --cnt[yu][xr+1];
                --cnt[yd+1][xl];
                ++cnt[yd+1][xr+1];
                sum[yu][xl]+=i;
                sum[yu][xr+1]-=i;
                sum[yd+1][xl]-=i;
                sum[yd+1][xr+1]+=i;
                pow2[yu][xl]+=1ll*i*i;
                pow2[yu][xr+1]-=1ll*i*i;
                pow2[yd+1][xl]-=1ll*i*i;
                pow2[yd+1][xr+1]+=1ll*i*i; 
            }
    //        for(int i=1;i<=m;++i,printf("
    "))
    //            for(int j=1;j<=m;++j)
    //                printf("%d ",cnt[i][j]);
            for(int i=1;i<=m;++i)
                for(int j=1;j<=m;++j)
                {
                    cnt[i][j]=cnt[i][j]+cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1];
                    sum[i][j]=sum[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
                    pow2[i][j]=pow2[i][j]+pow2[i-1][j]+pow2[i][j-1]-pow2[i-1][j-1];
                }        
    //        for(int i=1;i<=m;++i,printf("
    "))
    //            for(int j=1;j<=m;++j)
    //                printf("%d ",cnt[i][j]);
            s0=0;
            for(int i=1;i<=n;++i) s1[i]=0;
            n3=0;
            for(int i=1;i<=m;++i)
                for(int j=1;j<=m;++j)
                {
                    if(!cnt[i][j]) ++s0;
                    else if(cnt[i][j]==1) ++s1[sum[i][j]]; 
                    else if(cnt[i][j]==2)
                    {
                        ++n3;
                        s2[n3].a=(sum[i][j]+sqrt(2*pow2[i][j]-sum[i][j]*sum[i][j]))/2;
                        s2[n3].b=sum[i][j]-s2[n3].a;
                        //if(s2[n3].a>s2[n3].b) swap(s2[n3].a,s2[n3].b);
                    }
                }
             //printf("s0=%d
    ",s0);
             //for(int i=1;i<=n;++i) if(s1[i]) printf("s1[%d]=%d
    ",i,s1[i]); 
             ans=m*m-s0;
             k1=k2=0;
             for(int i=1;i<=n;++i)
                 if(s1[i]>=k1)
                 {
                     k2=k1;
                     k1=s1[i];
                 }
                 else if(s1[i]>k2) k2=s1[i];
             tmp=k1+k2;
             sort(s2+1,s2+n3+1,cmp);
             last=0;
             now=1;
             while(now<=n3)
             {
                 last=now;
                 while(now<=n3 && s2[now].a==s2[last].a && s2[now].b==s2[last].b) ++now;
                 tmp=max(tmp,s1[s2[last].a]+s1[s2[last].b]+now-last);
             //    printf("s1[%d]=%d s2[%d]=%d two=%d
    ",s2[last].a,s1[s2[last].a],s2[last].b,s1[s2[last].b],now-last);
             }
             ans-=tmp;
             printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    [core java学习笔记][第五章继承]
    [core java学习笔记][第四章对象与类]
    【转载】Maven中的BOM概念
    【转载】关于docker某些有用的文章
    【转载】linux Jumpserver跳板机堡垒机部署安装使用教程
    四:(之五)Dockerfile语法梳理和实践
    四:FAQ附录(容器交互,镜像交互,镜像导出)
    四:(之四)基于已有镜像构建自己的Docker镜像
    四:(之三)制作镜像和一些docker命令
    四:(之一和之二) docker架构和底层技术分析(C/S架构)
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14050227.html
Copyright © 2020-2023  润新知