zoukankan      html  css  js  c++  java
  • [SDOI2011] 打地鼠

    题面

        最简单暴力的办法就是分别枚举R和C,然后再暴力判断这组R和C是否可行,复杂度取决于你判断的暴力程度。。。。

        加入判断可以做到 O(N^2),那么就是总复杂度就是O(N^4)。

        先不说这是否能过,判断 O(N^2)该怎么做?

        这里我们用到了二维差分。因为二分差分可以把二维区间加变成只修改四个点,而前缀和就对应这个位置的原数,很适合做这个题。

        我们判断的时候就直接扫描,p[][]代表差分数组,s[][]代表每个位置现在的数是多少(实则就是p[][]的二维前缀和)。到一个位置(i,j),若a[i][j]<s[i][j],则无解,返回false;

    否则要进行区间 [i~i+R,j~j+C]加 a[i][j]-s[i][j],通过修改p[][]实现。s[][]的计算公式为 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+p[i][j],这个画画图就明白了了。

        其实我们相当于扫到每个(i,j)时就知道了左上角打在这有多少次。

        而且其实最后复杂度到不了 O(N^4),原因在于枚举R和C的时候,R*C必须是 ∑a[i][j] 的约数,又∵ <=1e9的数最多有1000左右的约数,且R和C都是<=100的数,所以最外层枚举R和C的复杂度不到1000,是可以过这个题的。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=105;
    
    int n,m,t,a[N][N],p[N*2][N*2],ans=1;
    
    inline bool check(int x,int y){
    	memset(p,0,sizeof(p));
    	
    	for(int i=1,ad;i<=n;i++)
    	    for(int j=1;j<=m;j++){
    	    	p[i][j]+=p[i-1][j]+p[i][j-1]-p[i-1][j-1];
    	    	if(p[i][j]>a[i][j]) return 0;
    	    	
    	    	ad=a[i][j]-p[i][j];
    	    	p[i][j]+=ad,p[i][j+y]-=ad;
    	    	p[i+x][j]-=ad,p[i+x][j+y]+=ad;
    		}
    	
    	return 1;
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=m;j++) scanf("%d",a[i]+j),t+=a[i][j];
    	
    	 
    	for(int i=1,now;i<=n;i++) if(!(t%i)){
    		now=t/i;
    		for(int j=now==t?2:1;j<=m;j++) if(i*j>ans&&!(now%j)&&check(i,j)) ans=i*j;
    	}
    	
    	printf("%d
    ",t/ans);
    	return 0;
    }
    

      

  • 相关阅读:
    观察者模式
    字符串操作函数
    位域结构体的字节对齐
    备忘任务
    Linux编程下EAGAIN和EINTR宏的含义及处理
    Linux 中write()函数的出错情况及处理
    Nginx配置配置文件nginx.conf的设置
    Linux编程获取本地IP
    redis与memcached比较
    TCP通讯socket自定义协议的实现
  • 原文地址:https://www.cnblogs.com/JYYHH/p/11317350.html
Copyright © 2011-2022 走看看