设为首页 加入收藏

TOP

BZOJ 2241 SDOI2011 打地鼠 线性筛+二阶差分
2015-07-20 17:44:40 】 浏览:6856
Tags:BZOJ 2241 SDOI2011 线性 +二阶差分

首先声明:此题不满足二分条件,一切写二分的题解均为误解 请注意辨明!

题目大意:给定一个m*n的洞穴矩阵,每个洞穴里面有若干地鼠,我们需要选定一个r*c的锤子进行击打,每次击打必须保证r*c的范围内所有洞穴均有地鼠,且每次击打只会打掉每个洞穴恰好一只地鼠,求最小击打次数

m,n<=100

考虑一个1*8的洞穴,当我们把锤子设作1*4时可以完成击打,而1*3不能 故不满足单调性,二分不正确

但是一个性质是确定的:假设我们选定一个3*4的锤子可以完成击打,那么我们选定一个3*2的锤子也一定能完成击打

那么反过来,当我们选择一个3*2的锤子无法完成击打时,那么3*4的锤子一定无法完成击打

说白了这题是一个偏是积性函数

于是这题我们选择线性筛进行筛选 若r相同时c1无法完成击打,那么c1*p也无法完成击打

验证的话 首先选定锤子时打的方案是一定的,于是我们贪心,从左上至右下依次击打,每个位置击打的次数等于击打区域左上角洞穴的当前地鼠数量,当击打后任意洞穴地鼠数量不为零

然后验证的时候强行模拟是O( (mn)^2 )树套树可以变成O( mn*logm*logn )

但是这道题有修改而没有查询(每次查询节点时前面必须为零) 故我们选择O(1)修改O(n^2)查询的二阶差分

向左向上进行两次差分 然后每次修改如图

\

击打后整个区域都为零则可以完成击打

此外这题O(n^4)暴力都能过 而且只比正解慢了四毫秒 就连O(n^6)的暴力加点剪枝都过了0.0 什么情况究竟

<http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;">#include #include #include #include #define M 110 using namespace std; int m,n,cnt,a[M][M],map[M][M],sum,ans=0x7f7f7f7f; const int prime[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97},tot=25; int not_able[2][M]; bool Judge(int x,int y) { int i,j; if( sum%(x*y) ) return 0; memcpy(map,a,sizeof a); for(i=1;i<=m;i++) { for(j=1;j<=n;j++) { if(map[i][j]<0) return 0; if(i<=m-x+1&&j<=n-y+1) { int num=map[i][j]; map[i][j]-=num; map[i+x][j]+=num; map[i][j+y]+=num; map[i+x][j+y]-=num; } if(map[i][j]>0) return 0; } } ans=min(ans,sum/x/y); return 1; } bool Linear_Shaker(int num,bool flag,int Time) { int i,j; bool re=0; for(i=1;i<=(flagn:m);i++) { if(not_able[flag][i]!=Time) { if(flag) not_able[flag][i]=(Judge(num,i)0:Time); else not_able[flag][i]=(Linear_Shaker(i,1,++cnt)0:Time); } if(not_able[flag][i]!=Time) re=1; if(i^1) for(j=1;j<=tot&&i*prime[j]<=(flagn:m);j++) { if(not_able[flag][i]==Time||not_able[flag][prime[j]]==Time) not_able[flag][i*prime[j]]=Time; if(i%prime[j]==0) break; } } return re; } int main() { int i,j; cin>>m>>n; for(i=1;i<=m;i++) for(j=1;j<=n;j++) scanf("%d",&a[i][j]),sum+=a[i][j]; for(i=m;i;i--) for(j=n;j;j--) a[i][j]-=a[i-1][j]; for(i=m;i;i--) for(j=n;j;j--) a[i][j]-=a[i][j-1]; Linear_Shaker(0,0,++cnt); cout<

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇UVA - 10588 Queuing at the doct.. 下一篇UVA - 10733 The Colored Cubes (..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目