zoukankan      html  css  js  c++  java
  • 3.29省选模拟赛 矩形

    LINK:矩形

    一个大小为n的01方阵 m次询问 每次询问求出大小为a行b列的合法矩形的个数.

    一个矩阵合法当且仅当其边缘都是为1.

    (n,mleq 1500) 2s,256mb

    考虑暴力 预处理出 r[i][j],d[i][j] 分别表示向右向下延伸的最长长度。

    求答案的时候 枚举每个点 判断一下即可。

    考试的时候写了一个一维的st表 和 单调队列做了这个判断。

    两种方法时间复杂度一样 n^2m.

    考虑优化 从第一种方法中我们考虑采用bitset来优化.

    b[i][j][k]表示长度>=i 第j行 第k个位置向右延伸是否可行。

    c则维护向下延伸是否可行。这样 我们在每次询问的时候枚举行 然后利用c数组和b数据进行判断即可。

    不过维护c数组和b数组 时间复杂度为 n^3/w 空间复杂度也同样如此 计算一下空间 800多mb GG。

    考虑分块或者莫队。 这里考虑莫队。

    因为我们只要优化一下空间即可。 每次不需要维护那么多的b数组和c数组。

    对于b数组我们维护sqrt(n)个 莫队的时候 这个部分更新是n^2的 传递答案是 n^3/w的。

    考虑 第二维 发现c的第一维完全没用 所以直接扔了 内部c的更新是n^2的 没有传递答案 所以这样做复杂度为sqrt(n)n^2.

    综上发现空间变成了 sqrt(n) * n * n/32的。

    可以时间多了一个n^{2.5}次方 可以通过此题。

    值得一提的是 我在写的时候迷了半天不知道该怎么写 首先 明确莫队。

    莫队的第二维我写的时候也维护了一个sqrt(S) 没发现这个是不必要的 第二维单调递增。

    总时间复杂度 n^3 /w +n^2 m/ w+ n^{2.5}.

    const int MAXN=1510;
    int n,m,B;
    bitset<MAXN>b[101][MAXN],c[MAXN],cc;
    char a[MAXN][MAXN];
    int ans[MAXN],R[MAXN][MAXN],D[MAXN][MAXN];//分别表示向右最长延伸和向下最长延伸.
    vector<pii>g[MAXN][2];
    struct wy{int x,y,id;}t[MAXN];
    inline int cmp(wy a,wy b){return (a.y-1)/B==(b.y-1)/B?a.x<b.x:(a.y-1)/B<(b.y-1)/B;}
    inline void gx3(int op,int x,int y)
    {
    	if(y>n)return;
    	if(!g[y-1][op].size())return;
    	rep(0,g[y-1][op].size()-1,i)b[x][g[y-1][op][i].F][g[y-1][op][i].S]=0;
    }
    inline void gx1(int x,int y)//b bitset由x块更新到y块.
    {
    	while(x<y)
    	{
    		int st=x*B;
    		rep(1,B-1,i)
    		{
    			gx3(0,B,st+1),++st;
    			rep(1,n,j)b[i][j]=b[B][j];
    		}
    		gx3(0,B,st+1);++x;
    	}
    }
    inline void gx4(int op,int y)
    {
    	if(y>n)return;
    	if(!g[y-1][op].size())return;
    	rep(0,g[y-1][op].size()-1,i)c[g[y-1][op][i].F][g[y-1][op][i].S]=0;
    }
    inline void gx2(int x,int y)
    {
    	rep(x+1,y,i)gx4(1,i);
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	gt(n);gt(m);B=(int)sqrt(n*1.0);
    	rep(1,n,i){gc(a[i]),cc[i]=1;}
    	rep(1,n,i)
    	{
    		fep(n,1,j)
    		{
    			if(a[i][j]=='0')R[i][j]=0;
    			else R[i][j]=R[i][j+1]+1;
    			if(a[j][i]=='0')D[j][i]=0;
    			else D[j][i]=D[j+1][i]+1;
    			g[R[i][j]][0].pb(mk(i,j));
    			g[D[j][i]][1].pb(mk(j,i));
    		}
    	}
    	rep(1,m,i)
    	{
    		int x;gt(x);int y;gt(y);
    		t[i]=(wy){x,y,i};
    	}
    	sort(t+1,t+1+m,cmp);
    	int wl=0,wr=0;
    	rep(1,n,i)b[B][i]=cc;
    	for(int i=1;i<=m;++i)
    	{
    		if(wl*B<t[i].y)
    		{
    			wr=0;
    			rep(1,n,j)c[j]=cc;
    			int ww=(t[i].y-1)/B+1;
    			gx1(wl,ww);wl=ww;
    		}
    		while(wr<t[i].x){gx2(wr,t[i].x);wr=t[i].x;}
    		int ww=0;
    		int s1=t[i].y%B==0?B:t[i].y%B;
    		int s2=t[i].x%B==0?B:t[i].x%B;
    		int x=t[i].x,y=t[i].y;//x行y列
    		rep(1,n-x+1,j)ww=ww+(b[s1][j]&b[s1][j+x-1]&c[j]&(c[j]>>(y-1))).count();
    		/*{
    			{rep(1,n,k)cout<<c[s2][j][k];cout<<endl;}
    			cout<<y-1<<endl;
    			cout<<((c[s2][j]>>(y-1)).count())<<endl;
    		}*/
    		//bitset<MAXN>ss;
    		//rep(1,n,j){rep(1,n,k)cout<<b[s1][j][k];cout<<endl;}
    		//rep(1,n,j){rep(1,n,k)cout<<c[s2][j][k];cout<<endl;}
    		//rep(1,n,j){ss=(c[s2][j]>>(y-1));rep(1,n,k)cout<<ss[k];cout<<endl;}
    		ans[t[i].id]=ww;
    	}
    	rep(1,m,i)put(ans[i]);
    	return 0;
    }
    

    最后 bitset的空间:一个空间一bit. 一般w=32或64.

    bitset的排列是从高位到地位排的所以判断的时候是右移而不是左移。

  • 相关阅读:
    描述一下 JVM 加载 class 文件的原理机制?
    Java 中会存在内存泄漏吗,请简单描述
    关于同步机制的一些见解
    Mybatis 一对一,一对多,多对一,多对多的理解
    关于JavaBean实现Serializable接口的见解
    Python 文件I/O
    Python 模块
    Python 函数
    Python time tzset()方法
    Python time time()方法
  • 原文地址:https://www.cnblogs.com/chdy/p/12601929.html
Copyright © 2011-2022 走看看