ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NFLSOJ #12458. 「NOIP2021模拟赛0929知临」棋盘(双栈模拟队列)

2021-09-29 21:31:07  阅读:211  来源: 互联网

标签:0929 NFLSOJ int res 复杂度 矩阵 mid lft 模拟


题面传送门

之前不知道有”双栈模拟队列“这回事(主要是 9.23 模拟那场 T2 拿分治水过了就没管正解),写篇题解记录一下(

首先我们可以很自然地想到一个 DP,\(dp_{i,j}\) 表示有多少组到达第 \(i\) 行第 \(j\) 列所在格子的方案数,转移就从前两行刷表转移即可,复杂度 \(q^2n\),大约可以获得 \(30\) 分的好成绩(雾

考虑优化。注意到转移可以写成矩阵的方式,并且列数很小,只有 \(20\),因此可以想到矩阵乘法优化 DP。考虑离线建出最后的网格图,那么每次询问肯定是网格图上行在一段区间内的子矩形,经典的线段树维护矩阵乘法的模型,每次询问都求一遍区间矩阵乘积复杂度 \(qn^3\log q\),可以获得 \(70\) 分的好成绩。

继续优化。考虑这样一个事实:我们每次乘的矩阵中,\(1\) 的个数是 \(\mathcal O(n)\) 的,也就是说转移矩阵是一个稀疏矩阵,换句话说如果我们新加入一行,我们可以在 \(\mathcal O(n)\) 的时间内算出新的 DP 值,而不必 \(n^3\) 地跑一遍矩阵乘法。碰到这类插入复杂度很小,但合并复杂度很高的题可以想到将操作尽量转化为插入操作。怎么转化呢?一种常见的方法是分治,虽然应用到此题上不是不行,但对于此题而言使用分治复杂度会多一个 \(\log\),不知道能不能通过。

注意到我们每次都是在头添加元素,尾删除元素,也就是说添加/删除元素的过程组成了一个队列结构。因此考虑双栈模拟队列,具体来说我们实时维护一个端点 \(mid\),然后维护 \(L\to mid,mid+1\to R\) 的转移矩阵。考虑每次操作带来的影响:

  • 加入操作:我们先将加入的行放在右半边,显然我们可以 \(\mathcal O(n)\) 地算出新加入的行的贡献
  • 删除操作:直接令左端点加 \(1\)。如果左半边非空那就不用管它了,否则将右半部分全部加入左半部分中,具体操作是,先令 \(mid=R\),然后设 \(dp_x\) 表示从第 \(x\) 列到第 \(mid\) 列的子矩形的转移矩阵,然后我们从第 \(R\) 列开始向 \(L\) 列扩展,每次新加入一列贡献可以 \(\mathcal O(n)\) 地算出,这样可以在 \(\mathcal O((R-L+1)·n)\) 的时间内算出新的转移矩阵。
  • 查询操作:将左右部分合并起来。右半部分我们实时维护着,它的贡献直接调用即可。左半部分的贡献就调用每次重构时的 \(dp\) 数组即可。记当前最上边一行在完整的图形中是第 \(L\) 行,那么左半部分的贡献就是 \(dp_L\)。

显然每个点最多被重构一次,因此删除总复杂度均摊 \(qn^2\),而查询和加入复杂度都是单次 \(\mathcal O(n)\) 的,因此总复杂度 \(qn^2\)。

还有一点是由于这题马的移动轨迹涉及到前两行,因此 DP 状态还要记录上一行的状态,所以常数略有点大。

const int MAXQ=1e5;
const int MAXN=20;
int n,qu,mid,L=1,R=0;char s[MAXQ+5][MAXN+5];
struct dat{
	int a[MAXN+5][MAXN+5][2];
	dat(){memset(a,0,sizeof(a));}
	void clear(){memset(a,0,sizeof(a));}
};//0:current row 1:last row
dat rit[2],lft[2][MAXQ+5];
dat ins(dat x,int r){
	dat ret;
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ret.a[i][j][1]=x.a[i][j][0];
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(s[r][j]!='#'){
		if(j-2>=1) ret.a[i][j][0]=(ret.a[i][j][0]+x.a[i][j-2][0])%MOD;
		if(j+2<=n) ret.a[i][j][0]=(ret.a[i][j][0]+x.a[i][j+2][0])%MOD;
		if(j-1>=1) ret.a[i][j][0]=(ret.a[i][j][0]+x.a[i][j-1][1])%MOD;
		if(j+1<=n) ret.a[i][j][0]=(ret.a[i][j][0]+x.a[i][j+1][1])%MOD;
	} return ret;
}
int main(){
	freopen("chess.in","r",stdin);
	freopen("chess.out","w",stdout);
	scanf("%d%d",&n,&qu);
	for(int _=1;_<=qu;_++){
		static char opt[10];scanf("%s",opt+1);
		if(opt[1]=='A'){
			R++;scanf("%s",s[R]+1);
			if(R==mid+1){
				rit[0].clear();rit[1].clear();
				for(int i=1;i<=n;i++) rit[0].a[i][i][0]=(s[R][i]=='.');
			} else if(R==mid+2){
				rit[0]=ins(rit[0],R);
				for(int i=1;i<=n;i++) rit[1].a[i][i][0]=(s[R][i]=='.');
			} else rit[0]=ins(rit[0],R),rit[1]=ins(rit[1],R);
//			for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",rit[0].a[i][j][0]," \n"[j==n]);
//			for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",rit[1].a[i][j][0]," \n"[j==n]);
		} else if(opt[1]=='D'){
			L++;
			if(L>mid){
				mid=R;rit[0].clear();rit[1].clear();
				for(int i=L;i<=R;i++) lft[0][i].clear(),lft[1][i].clear();
				for(int i=1;i<=n;i++) lft[0][mid].a[i][i][0]=(s[mid][i]=='.');
				for(int i=1;i<=n;i++) lft[1][mid-1].a[i][i][0]=(s[mid-1][i]=='.');
				for(int i=mid-1;i>=L;i--) lft[0][i]=ins(lft[0][i+1],i);
				for(int i=mid-2;i>=L;i--) lft[1][i]=ins(lft[1][i+1],i);
			}
		} else {
			int x,y;scanf("%d%d",&x,&y);
			if(L>R){puts("0");continue;}
			if(s[L][x]=='#'||s[R][y]=='#'){puts("0");continue;}
			if(L==R){printf("%d\n",(x==y));continue;}
			if(R==mid){printf("%d\n",lft[0][L].a[y][x][0]);continue;}
			if(L>mid){printf("%d\n",rit[0].a[x][y][0]);continue;}
			int res=0;
			for(int i=1;i<=n;i++){
				if(i-2>=1) res=(res+1ll*lft[0][L].a[i][x][0]*rit[0].a[i-2][y][0])%MOD;
				if(i+2<=n) res=(res+1ll*lft[0][L].a[i][x][0]*rit[0].a[i+2][y][0])%MOD;
				if(i-1>=1) res=(res+1ll*lft[1][L].a[i][x][0]*rit[0].a[i-1][y][0])%MOD;
				if(i+1<=n) res=(res+1ll*lft[1][L].a[i][x][0]*rit[0].a[i+1][y][0])%MOD;
				if(i-1>=1) res=(res+1ll*lft[0][L].a[i][x][0]*rit[1].a[i-1][y][0])%MOD;
				if(i+1<=n) res=(res+1ll*lft[0][L].a[i][x][0]*rit[1].a[i+1][y][0])%MOD;
			} printf("%d\n",res);
		}
	}
	return 0;
}
/*
5 100
Add .....
Add .....
Del
Del
Add .....
Add .....
Del
Del
Add .....
Add .....
Que 2 4
Add .....
Add .....
Que 2 4
Del
Que 2 3
Del
Que 2 4
*/

标签:0929,NFLSOJ,int,res,复杂度,矩阵,mid,lft,模拟
来源: https://www.cnblogs.com/ET2006/p/NFLSOJ-12458.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有