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的排列是从高位到地位排的所以判断的时候是右移而不是左移。

原文地址:https://www.cnblogs.com/chdy/p/12601929.html

时间: 2024-11-08 18:50:57

3.29省选模拟赛 矩形的相关文章

2018/3/29 省选模拟赛 80

我真是太菜了... T1 10分纯暴力没写,20分容斥也没写(人就是懒死的).还有30分矩乘不会 正解 <IOI2018 中国国家集训队第一阶段作业题解部分 - 杭州第二中学 吴瑾昭.pdf>最后一题 T2  以为自己能拿到50分,但是其实那个暴力算法只能过10分的点,n=2000的20分数据用n^3带剪枝过不了,所以拿了30分. 正解 <计数与期望问题选讲 CLJ.pdf>最后一题 我记得我以前好像看到过这个文档但是没读过..今天读一下 T3 依然是分情况50分,30分树归20分

2018.6.29 省选模拟赛

*注意:这套题目应版权方要求,不得公示题面. 从这里开始 Problem A 小D与电梯 Problem B 小D与田野 Problem C 小D与函数 Problem A 小D与电梯 题目大意 假设电梯在0层,容量无限大.给定$n$个人的到达时间和要去的楼层.电梯上下一层楼花费的时间为1,电梯开关门.乘客上下的耗时不计,电梯可以停留在某一层楼.问将所有人送达到目的地,并让电梯回到0层的最少耗时. 先按到达时间将所有人排序.显然,每次电梯运输的人是一段连续的区间中的人. 用$f[i]$表示将前$

3.29省选模拟赛 除法与取模 dp+组合计数

LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采用二进制状压是不明智的 2的个数最多为13个 2^13也同样到达了1e4的复杂度. 考虑 hash状压 即 2的个数有x个 那么我们就有状态w表示2还有x个. 这样做的原因是把一些相同的东西给合并起来 而并非分散开来.即有多个2直接记录有多少个即可. 可以发现 这样做不同的除数最多只有5个 状态量较

@省选模拟赛03/16 - T3@ 超级树

目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取一棵深度为 k 的满二叉树,对每个节点向它的所有祖先连边(如果这条边不存在的话). 例如,下面是一个 4-超级树: 请统计一棵 k-超级树 中有多少条不同的简单有向路径,对 mod 取模. input 一行两整数 k, mod. output 一行一整数表示答案. example input1: 2

4.3 省选模拟赛 石子游戏 树上博弈

注意观察题目 每个点都只能将石子给自己的两个儿子 且石子个数>=1. 显然 这是一个阶梯NIM. 只有和最后一层的奇偶性相同的层才会有贡献 证明也很显然. 那么这其实就是近乎NIM游戏了 胜负自然取决于所有有贡献的石子堆的异或和. 但是 上午我傻了的一点 没有分清SG函数和NIM游戏的联系. 在NIM游戏中SG函数其实就是每个有贡献的石子堆的石子数. 再来看这道题 由于异或和一定 暴力枚举移动哪一堆石子 判断是否可行即可. 这个操作其实是 NIM游戏的证明问题了.解决的方案是 观察一下移动后造成

省选模拟赛某题 图3.29

LINK:图 求出一张图中 生成树森林或基环树+生成树森林的每个方案的贡献之和.n<=16,m<=(n-1)*n/2. 图中只允许最多出现一个环 一个方案的贡献为 这张图的各个联通块大小之积. (爆搜能拿很多分数 因为爆搜的上界并非2^m 类似于一个C(m,n)+C(m,n-1)+C(m,n-2)+...的复杂度. 由于最多只有n条边 且图中最多只有一个环 但是由于边数过多考虑状压点. 当求生成树森林的时候 不难想到f[i]表示i个点的集合生成树的数量. 对于某个集合i来说暴力跑矩阵树定理 最

2018.3.10 省选模拟赛

从这里开始 概况 Problem A 三元组 Problem B 攻略 Problem C 迂回 概况 这是省选T1合集?还是欢乐AK赛? 全班一半以上的人三道题都会做qwq. Doggu还剩一小时时以为自己AK了,然后玩了一小时.虽然最终被卡了20分的常数. ZJC 1个半小时AK?Excuse me? 我这条大咸鱼到最后10分钟才敲完了T1,然后发现线段树要T掉. 发自内心鄙视垃圾出题人卡常数,本来的欢乐AK变成280. 教练给我们考4个小时的试,题面上也这么写的,看题解,woc,考试时间3

2018.2.12 省选模拟赛

题目大意 (题目很简洁了,不需要大意) 其实显而易见地可以发现,当被卡一次后后面的路程都是固定了的. 可以用类似动态规划的思想来进行预处理.现在的问题就是怎么知道在某个位置刚等完红灯然后出发会在哪个路口再次被卡. 尝试画一画图: 其中横轴表示位置,纵轴表示时间,长方体表示红灯时段.有用的部分长度只有$r + g$,所以在模意义下弄一下就可以减少很多重复和无用状态: 但是这样仍然不好处理上面提到的问题,考虑让线段横着走,第一个撞着的长方形就是答案.为了实现这个目标,就每个长方形向下移动一段(移动的

xjoi省选模拟赛_14

T1 发现 对于当前 投出 奇数次向上的概率为 p 那么 若加入一个 pi=0.5 的骰子 发现  p奇 +1=p奇 * 0.5+p偶 * 0.5 = p偶+1  也就是说 只要方案中存在一个 p=0.5 的骰子 这个方案必然合法  : 1 #include <bits/stdc++.h> 2 #define N 100 3 #define eps 1e-7 4 using namespace std; 5 typedef long double ldb; 6 int t,n; 7 ldb A