您的位置:首页 > 其它

2241: [SDOI2011]打地鼠

2017-07-19 22:29 267 查看
题目链接

题目大意:给定一个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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: