首页 > 其他分享 >P9351 题解

P9351 题解

时间:2024-08-03 17:07:30浏览次数:13  
标签:min int 题解 tp ++ P9351 fd dis

P9351

思路

观察到一次覆盖操作相当于 \((u,v)\) 向 \((u,v)\) 为中心的一个矩形挖去四个角中每个点连代价为 \(1\) 的边。

因为 \(r\le c\),\(r\le \sqrt {rc}\)。暴力是 01bfs,到每个点处理覆盖操作时枚举行一边,用 \(n\) 个并查集维护每行没有被删去的后继。对于每个点需要枚举 \(\min(2\times n,r)\) 行,每个点只被入队一次。复杂度 \(O(rc\sqrt {rc})\)。

瓶颈在于枚举一行时有可能整行都没有要入队的点。

观察发现,除了最后一次覆盖操作以外,每一次覆盖操作都只让矩形边界上的点入队一定不劣。如果通过覆盖操作到达矩形边界内一个点有意义,那一定有一个原来的白连通块从这个点跨到矩形外面去,那这样之前通过覆盖操作到达矩形和连通块相交的位置即可。

这样每次一个点向 \(4\) 条边中的点连边,维护每行每列的未操作后缀的并查集。复杂度 \(O(rc)\)

code

int n,m,d;
int sx,sy,ex,ey;
char s[maxn];
vector<vector<int>> a,dis;
int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
vector<vector<int>> f;
int fd(int id,int x){
	if(x==f[id][x])return x;
	return f[id][x]=fd(id,f[id][x]);
}
pii q[maxn];int h=1,t=0;
pii st[maxn];int tp;
int ans;
void work(){
	n=read(),m=read(),d=read();
	a.resize(n+1),dis.resize(n+1);
	for(int i=1;i<=n;i++){
		a[i].resize(m+1),dis[i].resize(m+1);
		for(int j=1;j<=m;j++)dis[i][j]=inf;
	}
	f.resize(n+m+1);
	for(int i=1;i<=n;i++){
		f[i].resize(m+2);f[i][m+1]=m+1;
		for(int j=1;j<=m;j++)f[i][j]=j;
	}
	for(int i=n+1;i<=n+m;i++){
		f[i].resize(n+2);f[i][n+1]=n+1;
		for(int j=1;j<=n;j++)f[i][j]=j;
	}
	sx=read(),sy=read(),ex=read(),ey=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)a[i][j]=(s[j]=='.');
	}
	dis[sx][sy]=0,q[++t]={sx,sy};
	int cnt=0;ans=inf;
	while(h<=t){
		tp=0;
		while(h<=t){
			int u=q[h].fi,v=q[h].se;h++;
			if(abs(u-ex)<=d+1&&abs(v-ey)<=d+1&&abs(u-ex)+abs(v-ey)<=2*d)ans=min(ans,dis[u][v]+1);
			f[u][v]=fd(u,v+1);f[v+n][u]=fd(v+n,u+1);
			if(1){	
				int i=max(1,u-d);
				int l=max(1,(i==u-d||i==u+d)?v-d+1:v-d);
				int r=min(m,(i==u-d||i==u+d)?v+d-1:v+d);
				for(int j=fd(i,l);j<=r;j=fd(i,j)){
					if(dis[i][j]>dis[u][v]+1){
						dis[i][j]=dis[u][v]+1;
						st[++tp]={i,j};
					}
					f[i][j]=fd(i,j+1);f[j+n][i]=fd(j+n,i+1);
				}
			}
			if(1){	
				int i=min(n,u+d);
				int l=max(1,(i==u-d||i==u+d)?v-d+1:v-d);
				int r=min(m,(i==u-d||i==u+d)?v+d-1:v+d);
				for(int j=fd(i,l);j<=r;j=fd(i,j)){
					if(dis[i][j]>dis[u][v]+1){
						dis[i][j]=dis[u][v]+1;
						st[++tp]={i,j};
					}
					f[i][j]=fd(i,j+1);f[j+n][i]=fd(j+n,i+1);
				}
			}
			if(1){	
				int i=max(1,v-d);
				int l=max(1,(i==v-d||i==v+d)?u-d+1:u-d);
				int r=min(n,(i==v-d||i==v+d)?u+d-1:u+d);
				for(int j=fd(i+n,l);j<=r;j=fd(i+n,j)){
					if(dis[j][i]>dis[u][v]+1){
						dis[j][i]=dis[u][v]+1;
						st[++tp]={j,i};
					}
					f[i+n][j]=fd(i+n,j+1);f[j][i]=fd(j,i+1);
				}
			}
			if(1){	
				int i=min(m,v+d);
				int l=max(1,(i==v-d||i==v+d)?u-d+1:u-d);
				int r=min(n,(i==v-d||i==v+d)?u+d-1:u+d);
				for(int j=fd(i+n,l);j<=r;j=fd(i+n,j)){
					if(dis[j][i]>dis[u][v]+1){
						dis[j][i]=dis[u][v]+1;
						st[++tp]={j,i};
					}
					f[i+n][j]=fd(i+n,j+1);f[j][i]=fd(j,i+1);
				}
			}
			for(int i=0;i<4;i++){
				int nx=u+fx[i][0],ny=v+fx[i][1];
				if(nx<=0||nx>n||ny<=0||ny>m)continue;
				if(!a[nx][ny])continue;
				if(dis[nx][ny]>dis[u][v]){
					dis[nx][ny]=dis[u][v],q[++t]={nx,ny};
				}
			}
		}
		h=1,t=0;
		cnt++;
		if(dis[ex][ey]!=inf||ans==cnt)break;
		for(int i=1;i<=tp;i++){
			pii p=st[i];
			if(dis[p.fi][p.se]!=cnt)continue;
			q[++t]=p;
		}
	}
	printf("%d\n",min(ans,dis[ex][ey]));
}

标签:min,int,题解,tp,++,P9351,fd,dis
From: https://www.cnblogs.com/yhddd/p/18340789

相关文章

  • 20240803题解
    话说T3都把式子推出来了结果忘记差分约束怎么写了。光线(light)题面:有\(n\)个玻璃板,第\(i\)个玻璃板的透光率为\(a_i\%\),反射率为\(b_i\%\),有大小为\(1\)个单位的一束光从第\(1\)个玻璃板开始,有多少光能穿透\(n\)层玻璃板。题解:考虑\(n=2\)时,可以简单算出两个玻璃板组合后的反......
  • 第三次测试题解
    问题F:求多个数的最大公约数multigcd[1*]:`#includeincludeincludeincludeusingnamespacestd;intfun(inta,intb){returnb==0?a:fun(b,a%b);}intmain(){intn;cin>>n;vectora(n+1,0);for(inti=1;i<=n;i++)scanf("%d",&a[i]);intans......
  • 镜面质数 题解
    题目id:20313题目描述如果一个质数镜像反转(即将该数各个位上数字反转)后仍然是质数,那么就称这个质数为镜像质数。例如质数\(13\)反转后为\(31\),则\(13\)为一个镜像质数。现在给定一个整数\(N\),请求出整数\(1\simN\)范围内有几个镜像质数。注意:求范围内的镜像质数时,质数和镜像反......
  • CF1946F Nobody is needed 题解
    Nobodyisneeded推销我的洛谷博客。题意多组数据。给定一个长度为\(n\)的排列\(a\),你需要回答\(q\)组询问,每组询问给出\(l,r\),求有多少个子序列\(t\)使得:\(l\leqslantt_1<t_2<\cdots<t_k\leqslantr\)。\(a_{t_i}|a_{t_{i+1}}(1\leqslanti<k)\)......
  • NSSCTF Web 题解 Write up
    NSSCTFWeb题解Writeup一、Do_you_know_http1、开题2、分析页面显示请使用“WLLM”浏览器,我没听说过“WLLM”浏览器,那首先去User-Agent修改访问的浏览器。用HackBar分析,将UA的值改成WLLM。用EXECUTE请求页面显示你只可以在本地正常阅读,并给出了ip。那简单,还是用HackB......
  • AGC013B 题解
    注意到只要随便dfs,如果没有可以走的点,说明这个端点满足要求。因为有两个端点,所以从同一个点开始搜两次,拼在一起就行了。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+5;vector<int>e[N];intn,m;boolvis[N];voiddfs(in......
  • AGC009B 题解
    注意到如果把每一对胜者败者连边,可以得到一颗树:(例子)但是因为胜者每次只能和一个败者打,所以要用类似多叉转二叉的方法,让有不止一个孩子的节点变成有一个孩子和一个虚点。如图,原来\(1\)有三个儿子\(2,3,4\),通过转换,变成了上图。上图可以直接变成对战图(\(x2\tox1\to1)\):(原......
  • AGC049A 题解
    弱化版:CF280CGameonTree(有向图的限制变成一棵根节点为1的外向树)弱化版解法:根据期望线性性,\(Ans=\sum_{i=1}^nE(p_i)\)。其中\(p_i\)是\(i\)被选到的概率。因为对于\(i\)和\(i\)的祖先节点,某个点在这些店里是第一个备选的概率相同。所以\(p_i=\dfrac{1}{dep_i}\)......
  • joisc2017 D3T1 长途巴士 题解
    joisc2017D3T1长途巴士题解这是学校ACM欢乐赛的题,赛时想到做法了,但是因为我各种唐诗没写出来翻了转化题面我们发现,只可以踢掉检查站前面一个连续段的接水人,并且不能踢掉司机,考虑画出对整个路程表示的线段上图几个小点是检查点,考虑在每个检查点之前踢掉一段的人,容易发......
  • ABC269F 题解
    注意到第\(i\)行和第\(i+2\)行被删除的格子的排列顺序相同,格子上的数差了\(2m\)。于是处理出第\(i,i+1\)行的答案\(a_i,a_{i+1}\),有值的格子的个数\(c_i,c_{i+1}\)。令\(s(i)=\dfrac{(i-1)i}2\),也就是\(\sum_{j=1}^{i-1}j\)。第\(i,i+2,i+4\cdots\)行的和:\(a_i\t......