3.29省选模拟赛 矩形
LINK:矩形
一个大小为n的01方阵 m次询问 每次询问求出大小为a行b列的合法矩形的个数.
一个矩阵合法当且仅当其边缘都是为1.
\(n,m\leq 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的排列是从高位到地位排的所以判断的时候是右移而不是左移。