zoukankan      html  css  js  c++  java
  • CF364E Empty Rectangles

    一、题目

    点此看题

    二、解法

    众所周知一维问题变二维难度思维加倍,细节加倍,稍不注意就晕掉了。

    以防降智我们先考虑一维的情况,可以类似猫树分治,过中点处理出左边选 (x)(1) 的边界,右边选 (y)(1) 的边界,然后把 (x+y=k) 合并起来,用简单乘法原理算答案即可。

    二维的情况可以使用交替分治,也就是我们切 (x) 轴、切 (y) 轴一直交替进行。下面我们考虑切 (x) 轴的情况:

    我们枚举矩形的左边界 (i),然后把右边界当成指针一直往右扫,过程中维护"橙线",也就是达到 (x)(1) 的边界。显然随着右边界的移动上面橙线只会下移,下面的橙线只会上移,这个是具有单调性的,可以维护 (k) 个指针,算答案的时候还是简单乘法原理。

    现在来分析时间复杂度,设 (lenx,leny) 分别表示两维的长度,那么一次计算的复杂度是 (O(lenxcdot lenycdot k+lenx^2)),由于我们是对两维交替分治,所以时间复杂度 (O(nmklog nm))

    实现小细节:二维问题一定要注意区间的开闭,采用左开右闭可以减少很多细节。

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int M = 2505;
    #define ll long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,a[M][M],b[M][M],up[2][10];ll ans;
    int cal(int xl,int xr,int yl,int yr)
    {
    	return b[xr][yr]-b[xr][yl]-b[xl][yr]+b[xl][yl];
    }
    void cdq(int xl,int xr,int yl,int yr,int ty)
    {
    	if(xl==xr || yl==yr) return ;
    	if(xl+1==xr && yl+1==yr)
    	{
    		ans+=(cal(xl,xr,yl,yr)==k);
    		return ;
    	}
    	if(ty==0)
    	{
    		int mid=(xl+xr)>>1;
    		cdq(xl,mid,yl,yr,1);
    		cdq(mid,xr,yl,yr,1);
    		for(int i=yl;i<=yr;i++)
    		{
    			up[0][0]=up[1][0]=mid;
    			for(int j=1;j<=k+1;j++)
    				up[0][j]=xl,up[1][j]=xr;
    			for(int j=i+1;j<=yr;j++)
    			{
    				for(int p=1;p<=k+1;p++)
    				{
    					while(cal(up[0][p],mid,i,j)>=p)
    						up[0][p]++;
    					while(cal(mid,up[1][p],i,j)>=p)
    						up[1][p]--;
    				}
    				for(int p=0;p<=k;p++)
    					ans+=(up[0][p]-up[0][p+1])
    					*(up[1][k-p+1]-up[1][k-p]);
    			}
    		}
    	}
    	else
    	{
    		int mid=(yl+yr)>>1;
    		cdq(xl,xr,yl,mid,0);
    		cdq(xl,xr,mid,yr,0);
    		for(int i=xl;i<=xr;i++)
    		{
    			up[0][0]=up[1][0]=mid;
    			for(int j=1;j<=k+1;j++)
    				up[0][j]=yl,up[1][j]=yr;
    			for(int j=i+1;j<=xr;j++)
    			{
    				for(int p=1;p<=k+1;p++)
    				{
    					while(cal(i,j,up[0][p],mid)>=p)
    						up[0][p]++;
    					while(cal(i,j,mid,up[1][p])>=p)
    						up[1][p]--;
    				}
    				for(int p=0;p<=k;p++)
    					ans+=(up[0][p]-up[0][p+1])
    					*(up[1][k-p+1]-up[1][k-p]);
    			}
    		}
    	}
    }
    signed main()
    {
    	n=read();m=read();k=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
    			scanf("%1d",&a[i][j]);b[i][j]+=a[i][j];
    		}
    	cdq(0,n,0,m,1);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    【HDU3721】枚举+最长路
    满足要求的最长上升子序列(nlogn)
    Flask入门 表单Flask-wtf form原生 Bootstrap渲染(七)
    Flask入门之模板导入与块宏(六)
    Flask入门模板过滤器与测试器(五)
    Flask入门模板Jinja2语法与函数(四)
    Flask入门flask-script 蓝本 钩子函数(三)
    Flask入门request session cookie(二)
    Flask入门 flask结构 url_for 重定向(一)
    Django问卷调查项目思路流程
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15516918.html
Copyright © 2011-2022 走看看