• CF480E Parking Lot【最大子正方形-带修改】


    (博客园第(100)篇博客合影~

    题目链接

    题目解析

    被拿来作为考试题,我以为我会做来着,然而并不会(怎么好多人都做过这道题,果然是我太菜了嘤嘤嘤

    (三种做法的代码都放在了最后面

    法一

    如果你什么都不会,就像我一样,那么可以先敲出一个大暴力出来。

    (a[i][j])表示点((i,j))前面一列最大的连续空地长度,然后(n^2)枚举每个点作为正方形左上角,再枚举一个变量表示往右边延伸多少,一边枚举一边判断。

    (其实是因为想起了 这道题

    容易发现,这种方法求答案是(n^3)的(虽然普通情况下不会跑满),加上询问总时间复杂度(n^4)

    然后你就得到了(20pts)的好成绩(要知道全场只有我一个人得到了这个奇怪的分数

    考场上尝试优化,因为每次修改一个点之后,只有这个点周围的答案会改变,因为这个点可能把原来的答案正方形劈成很多半。但是发现有可能会存在很多个答案正方形,修改之后你无法判断这一坨会不会影响答案。

    法二

    怎么大家都会这种(dp)的方法啊

    定义(f[i][j])表示以点((i,j))为右下角的最大正方形的边长。

    如果((i,j))是障碍点,那么(f[i][j]=0),否则有(f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1)

    这个也比较好理解,考虑((i-1,j-1))往右下移一格,而((i-1,j),(i,j-1))的答案也会造成限制,所以取最小值,再加上拓展出来的(1)

    这个做法修改(O(1)),每次查询(O(n^2)),总时间复杂度(O(n^3))

    然后你就得到了(50pts)的好成绩(大众分

    法三

    我们想起了法一那个中道崩殂的优化,那个优化不可行,主要是因为修改之后最大值会变小,而我们不知道别的地方有没有其它最大值。

    但如果把询问离线下来,把加障碍变成减障碍,那么最大值就只会变大,而这个变大的最大值只能来源于修改的那一部分(冤有头债有主),所以就可以只处理修改的那一部分了。

    具体怎么求答案呢?

    如果有更大的答案的话,那么一定是包含这个障碍点的,也就是跨过这个障碍点所在行、所在列的。我们不妨从列的角度来考虑,先类似于悬线法那样预处理出每个点最多能够向左右延伸多远,这个在修改时可以(O(n))更新。查询时,由于修改点那一列一定在答案正方形内部,我们可以用单调队列来维护这一列向左向右延伸的距离,如果队首限制了正方形的发展,就弹出队首。由于需要一个具体的限制,所以可以用(check)的方式,去(check)更大的答案是否可行。平均下来查询大概是(O(n))的吧,可能常数会有点大,总复杂度(O(n^2))

    而如果真用悬线法的话,更新参数只需要更新去掉障碍点那一行,但是算答案还是要全部遍历一遍,因为悬线法是算的每个点对应的悬线对应的最大正方形,而更改了这个障碍点可能会影响到它下半部分任何一个点(我刚开始还以为只会影响这一列来着)。

    然后你就得到了(100pts)的真·好成绩


    ►Code View Ver.1

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 2005
    #define INF 0x3f3f3f3f
    #define LL long long
    int rd()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f*x;
    }
    int n,m,T;
    char s[N][N];
    int a[N][N],ans;
    int calc()
    {
    	int res=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    		{
    			int p=j,len=a[i][j];
    			while(p-j+1<=len) 
    			{
    				len=min(len,a[i][++p]),res=max(res,min(p-j+1,len));
    				if(res==ans) return ans;
    			}
    		}
    	return ans=res;
    }
    int main()
    {
    	freopen("parking.in","r",stdin);
    	freopen("parking.out","w",stdout);
    	n=rd(),m=rd(),T=rd();
    	for(int i=1;i<=n;i++)
    		scanf("%s",s[i]+1);
    	for(int i=1;i<=m;i++)
    		if(s[1][i]=='.') a[1][i]=1;
    	for(int i=2;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(s[i][j]=='.')
    				a[i][j]=a[i-1][j]+1;
    	while(T--)
    	{
    		int x=rd(),y=rd();
    		for(int i=x+1;i<=n;i++)
    		{
    			if(!a[i][y]) break;
    			a[i][y]-=a[x][y];
    		}
    		a[x][y]=0;
    		calc();
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
    

    ►Code View Ver.2

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 2005
    #define INF 0x3f3f3f3f
    #define LL long long
    int rd()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f*x;
    }
    int n,m,T;
    char s[N][N];
    int f[N][N],ans;
    void dp()
    {
    	ans=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			if(s[i][j]=='X') f[i][j]=0;
    			else f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;
    			ans=max(ans,f[i][j]);
    		}
    }
    int main()
    {
    	freopen("parking.in","r",stdin);
    	freopen("parking.out","w",stdout);
    	n=rd(),m=rd(),T=rd();
    	for(int i=1;i<=n;i++)
    		scanf("%s",s[i]+1);
    	while(T--)
    	{
    		int x=rd(),y=rd();
    		s[x][y]='X';
    		dp();
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    ►Code View Ver.3

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 2005
    #define INF 0x3f3f3f3f
    #define LL long long
    int rd()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f*x;
    }
    int n,m,T;
    char s[N][N];
    int f[N][N],ans,res[N];
    int l[N][N],r[N][N];
    pair<int,int> q[N];
    int xx,yy;
    int Q[N],hd,tl,tmp[N];
    void dp()
    {
    	ans=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			if(s[i][j]=='X') f[i][j]=0;
    			else f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1;
    			ans=max(ans,f[i][j]);
    		}
    }
    void Init()
    {
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    		{
    			if(s[i][j]=='X') l[i][j]=0;
    			else l[i][j]=l[i][j-1]+1;
    		}
    		for(int j=m;j>=1;j--)
    		{
    			if(s[i][j]=='X') r[i][j]=0;
    			else r[i][j]=r[i][j+1]+1;
    		}
    	}
    }
    bool check(int x)
    {
    	hd=1,tl=0;
    	for(int i=1;i<=n;i++)
    	{//维护左边 
    		while(hd<=tl&&l[Q[tl]][yy]>=l[i][yy]) tl--;
    		//维护单调增队列 如果当前可到位置比队列里的大 那么队列里的元素就不会成为瓶颈 
    		Q[++tl]=i;
    		while(hd<=tl&&Q[hd]<=i-x) hd++;//队首成为了限制
    		tmp[i]=l[Q[hd]][yy];
    	}
    	hd=1,tl=0;
    	for(int i=1;i<=n;i++)
    	{//维护右边 
    		while(hd<=tl&&r[Q[tl]][yy]>=r[i][yy]) tl--;
    		Q[++tl]=i;
    		while(hd<=tl&&Q[hd]<=i-x) hd++;
    		tmp[i]+=r[Q[hd]][yy]-1;
    	}
    	for(int i=x;i<=n;i++)
    		if(tmp[i]>=x) return 1;
    	return 0;
    }
    int main()
    {
    	freopen("parking.in","r",stdin);
    	freopen("parking.out","w",stdout);
    	n=rd(),m=rd(),T=rd();
    	for(int i=1;i<=n;i++)
    		scanf("%s",s[i]+1);
    	for(int i=1;i<=T;i++)
    	{
    		q[i].first=rd(),q[i].second=rd();
    		s[q[i].first][q[i].second]='X';
    	}
    	dp();
    	res[T]=ans;
    	Init();
    	for(int i=T-1;i>=1;i--)
    	{
    		xx=q[i+1].first,yy=q[i+1].second;
    		s[xx][yy]='.';
    		for(int j=1;j<=m;j++)
    		{
    			if(s[xx][j]=='X') l[xx][j]=0;
    			else l[xx][j]=l[xx][j-1]+1;
    		}
    		for(int j=m;j>=1;j--)
    		{
    			if(s[xx][j]=='X') r[xx][j]=0;
    			else r[xx][j]=r[xx][j+1]+1;
    		}
    		while(check(ans+1)) ans++;
    		res[i]=ans;
    	}
    	for(int i=1;i<=T;i++)
    		printf("%d
    ",res[i]);
    	return 0;
    }
    
    

    ►Code View Ver.4 悬线法 TLE

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 2005
    #define INF 0x3f3f3f3f
    #define LL long long
    int rd()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f*x;
    }
    int n,m,T;
    char s[N][N];
    int ans,res[N];
    int l[N][N],r[N][N],h[N][N],L[N][N],R[N][N];
    pair<int,int> q[N];
    void Init(int x)
    {
    	int t=1;
    	for(int j=1;j<=m;j++)
    	{
    		if(s[x][j]=='.') l[x][j]=t;
    		else L[x][j]=0,t=j+1;
    	}
    	t=m;
    	for(int j=m;j>=1;j--)
    	{
    		if(s[x][j]=='.') r[x][j]=t;
    		else R[x][j]=m+1,t=j-1;
    	}
    }
    void work(int y)
    {
    	for(int i=1;i<=n;i++)
    		if(s[i][y]=='.')
    		{
    			h[i][y]=h[i-1][y]+1;
    			L[i][y]=max(L[i-1][y],l[i][y]);
    			R[i][y]=min(R[i-1][y],r[i][y]);
    			int p=h[i][y],q=R[i][y]-L[i][y]+1;
    			ans=max(ans,min(p,q));
    		}
    }
    int main()
    {
    	freopen("parking.in","r",stdin);
    	freopen("parking.out","w",stdout);
    	n=rd(),m=rd(),T=rd();
    	for(int i=1;i<=n;i++)
    		scanf("%s",s[i]+1);
    	for(int i=1;i<=T;i++)
    	{
    		q[i].first=rd(),q[i].second=rd();
    		s[q[i].first][q[i].second]='#';
    	}
    	for(int i=1;i<=n;i++)
    		Init(i);
    	for(int i=1;i<=m;i++)
    		R[0][i]=m+1;
    	for(int i=1;i<=m;i++)
    		work(i);
    	res[T]=ans;
    	for(int i=T-1;i>=1;i--)
    	{
    		s[q[i+1].first][q[i+1].second]='.';
    		Init(q[i+1].first);
    		for(int j=1;j<=m;j++)
    			work(j);
    		//work(q[i+1].second);
    		res[i]=ans;
    	}
    	for(int i=1;i<=T;i++)
    		printf("%d
    ",res[i]);
    	return 0;
    }
    /*
    7 8 4 
    ........ 
    #.....#. 
    ........ 
    ........ 
    .#...... 
    ........ 
    ........ 
    1 5 
    6 4 
    3 5 
    4 6
    */
    /*
    ....#... 
    #.....#. 
    ....#... 
    .....@.. 
    .#...... 
    ...#.... 
    ........ 
    */
    
  • 相关阅读:
    uncategorized SQLException for SQL []; SQL state [99999]; error code [17004]; 无效的列类型: 1111; nested exception is java.sql.SQLException: 无效的列类型: 1111
    Oracle批量更新数据,使用begin end
    oracle数字返回为字符串时小时点前面的0缺失的问题
    nginx集群配置
    nginx解决跨域(前后端分离)
    Spring ContextLoaderListener And DispatcherServlet Concepts
    Troubleshooting Upgrade and CU Batch jobs stuck in a waiting status in Dynamics AX 2012
    Dynamics AX 2012 – Batch Jobs Not Executing
    Query Table Element
    PeopleCode JobRunStatus
  • 原文地址:https://www.cnblogs.com/lyttt/p/14039264.html
Copyright © 2020-2023  润新知