zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:physics(二维前缀和+二分+剪枝)

    题目传送门(内部题26)


    输入格式

    第一行有$3$个整数$n,m,q$。
    然后有$n$行,每行有一个长度为$m$的字符串,$+$表示正电粒子,$-$表示负电粒子。
    然后有$q$行,每行$2$个整数$x,y$,表示将第$x$行第$y$列的正电粒子修改为负电粒子,保证修改前第$x$行第$y$列的粒子带正电。


    输出格式

    有$q$行,每行一个整数此次修改后所有正电粒子能形成的最大的电场强度。


    样例

    样例输入:

    5 5 5
    +-+++
    +++++
    +++++
    +++++
    ++++-
    1 5
    2 2
    5 3
    2 3
    1 1

    样例输出:

    4
    3
    3
    2
    2


    数据范围与提示

    对于所有数据,$1leqslant n,mleqslant {10}^3,1leqslant qleqslant {10}^3$。


    题解

    $40\%$算法:

    纯暴力,暴力枚举端点,暴力枚举边长,暴力统计。

    时间复杂度:$Theta(n^5)$。

    期望得分:$40$分。

    实际得分:$40$分。

    $70\%$算法:

    如果你会二维前缀和,然后你以为你可以拿到$70$分,然后……依然是$40$分。

    但是我们发现,假设当前枚举的端点是$(i,j)$,边长为$k$,那么如果当前的正方形不行,那边长更大的肯定也不行;如果行,边长更小的肯定也行,那么我们要找的答案就在这行与不行的分界点上,而这个分界点你可以通过二分来找。

    时间复杂度:$Theta(n^2log n)$。

    期望得分:$40$分。

    实际得分:$40$分。

    $70\%pro$算法:

    题目中只会把正电子变为负电子,所以最大的电场强度一定是单调不递增的。

    进而,如果我们现在改变的这个电荷不在最大的正方形内,也就是它的改变对答案并没有影响,那么我们就可以标记它改变了,然后输出上一次的答案。

    如果它在最大正方形里,那么暴力再来一遍好啦。

    在二分的时候,如果已经不能出现比现在已经计算出来的答案更大的答案,就直接$continue$掉好啦。

    由于强大的剪枝,你就可以用这个算法$A$掉这道题了,但是仍能被极端数据卡掉。

    时间复杂度:$Theta(n^2log n)$。

    期望得分:$70$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,q;
    char ch[1001];
    int Map[1001][1001],sum[1001][1001];
    int maxn,ans=1001;
    pair<int,int> pre;
    int main()
    {
    	scanf("%d%d%d",&n,&m,&q);
    	maxn=min(n,m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",ch+1);
    		for(int j=1;j<=m;j++)
    		{
    			if(ch[j]=='+')Map[i][j]=1;
    			sum[i][j]=Map[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    		}
    	}
    	while(q--)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		Map[x][y]=0;
    		if(x<pre.first||y<pre.second||x>pre.first+ans-1||y>pre.second+ans-1)
    		{
    			printf("%d
    ",ans);
    			continue;
    		}
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    				sum[i][j]=Map[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    		ans=0;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    			{
    				int lft=1,rht=min(maxn,min(n-i+1,m-j+1)),res=0;
    				if(rht<=ans)break;
    				while(lft<=rht)
    				{
    					int mid=(lft+rht)>>1;
    					if(sum[i+mid-1][j+mid-1]-sum[i+mid-1][j-1]-sum[i-1][j+mid-1]+sum[i-1][j-1]==mid*mid){lft=mid+1,res=mid;}
    					else rht=mid-1;
    					if(rht<=ans)break;
    				}
    				if(res>ans)
    				{
    					ans=res;
    					pre=make_pair(i,j);
    				}
    			}
    		printf("%d
    ",ans);
    		maxn=ans;
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Top 10 Free IT Certification Training Resources
    在线学编程!十大IT在线教育网站推荐
    2016年国际十大科技新闻解读
    2016上半年度私有云提供商排行榜 :华为位居第一
    12 Top Open Source Data Analytics Apps
    Careers/Staffing Index
    top 9 Cloud Computing Failures
    344. Reverse String
    283. Move Zeroes
    DataContract with Json.Net
  • 原文地址:https://www.cnblogs.com/wzc521/p/11474527.html
Copyright © 2011-2022 走看看