题目大意:给定一个m*n的洞穴矩阵,每个洞穴里面有若干地鼠,我们需要选定一个r*c的锤子进行击打,每次击打必须保证r*c的范围内所有洞穴均有地鼠,且每次击打只会打掉每个洞穴恰好一只地鼠,求最小击打次数
题解:由于数据水,这题 O((nm)3),O((nm)2),二分乱搞都能过……
首先枚举长和宽,然后判断可行性,判断的时候就是二维区间修改+单点查询,然后用二维前缀和搞一下就可以了
我的收获:强强强
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define M 105//我开始写1005慢成狗
int n,m,sum,a[M][M],s[M][M];
bool ok(int x,int y){
if(sum%(x*y)) return 0;
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
int t=a[i][j]+s[i][j];
if(t<0) return 0;
if(!t) continue;
if(i+x>n+1||j+y>m+1) return 0;//出界,注意是n+1
s[i][j]-=t,s[i+x][j]+=t,s[i][j+y]+=t,s[i+x][j+y]-=t;
}
return 1;
}
void work()
{
int ans=0;
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
if(i*j>ans&&ok(i,j)) ans=i*j;//要写上i*j>ans!!,从大到小便于剪枝
printf("%d\n",sum/ans);
}
void init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),sum+=a[i][j];
}
int main()
{
init();
work();
return 0;
}