zoukankan      html  css  js  c++  java
  • BZOJ2241 [SDOI2011]打地鼠 【模拟】

    题目

    打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中。玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高。
    游戏中的锤子每次只能打一只地鼠,如果多只地鼠同时探出头,玩家只能通过多次挥舞锤子的方式打掉所有的地鼠。你认为这锤子太没用了,所以你改装了锤子,增加了锤子与地面的接触面积,使其每次可以击打一片区域。如果我们把地面看做MN的方阵,其每个元素都代表一个地鼠洞,那么锤子可以覆盖RC区域内的所有地鼠洞。但是改装后的锤子有一个缺点:每次挥舞锤子时,对于这RC的区域中的所有地洞,锤子会打掉恰好一只地鼠。也就是说锤子覆盖的区域中,每个地洞必须至少有1只地鼠,且如果某个地洞中地鼠的个数大于1,那么这个地洞只会有1只地鼠被打掉,因此每次挥舞锤子时,恰好有RC只地鼠被打掉。由于锤子的内部结构过于精密,因此在游戏过程中你不能旋转锤子(即不能互换R和C)。
    你可以任意更改锤子的规格(即你可以任意规定R和C的大小),但是改装锤子的工作只能在打地鼠前进行(即你不可以打掉一部分地鼠后,再改变锤子的规格)。你的任务是求出要想打掉所有的地鼠,至少需要挥舞锤子的次数。
    Hint:由于你可以把锤子的大小设置为1*1,因此本题总是有解的。

    输入格式

    第一行包含两个正整数M和N;

    下面M行每行N个正整数描述地图,每个数字表示相应位置的地洞中地鼠的数量。

    输出格式

    输出一个整数,表示最少的挥舞次数。

    输入样例

    3 3

    1 2 1

    2 4 2

    1 2 1

    输出样例

    4

    提示

    【样例说明】

    使用2*2的锤子,分别在左上、左下、右上、右下挥舞一次。

    【数据规模和约定】

    对于100%的数据,1<=M,N<=100,其他数据不小于0,不大于10^5

    题解

    模拟加一些优化
    直接枚举锤子长宽检验
    优化:
    ①锤子面积一定是地鼠总和的因子
    ②覆盖当前左上角的地鼠方式唯一固定
    ③如果地鼠总和除以锤子面积不比当前答案优,不检验

    虽然说是(O(n^6))
    但实际并没有那么多
    小非常多
    玄学地过了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 105,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int sum,s[maxn][maxn],t[maxn][maxn],n,m,r,c,cnt,ans = INF;
    void check(){
    	REP(i,n) REP(j,m) t[i][j] = s[i][j];
    	REP(i,n) REP(j,m){
    		if (i + r - 1 > n || j + c - 1 > m){
    			if (t[i][j]) return;
    			continue;
    		}
    		else if (t[i][j]){
    			int tmp = t[i][j];
    			for (int x = 0; x < r; x++)
    				for (int y = 0; y < c; y++){
    					if (t[i + x][j + y] < tmp) return;
    					t[i + x][j + y] -= tmp;
    				}
    		}
    	}
    	ans = min(ans,sum / (r * c));
    }
    int main(){
    	n = read(); m = read();
    	REP(i,n) REP(j,m) sum += (s[i][j] = read());
    	for (r = 1; r <= n; r++)
    		for (c = 1; c <= m; c++)
    			if (sum % (r * c) == 0 && sum / (r * c) < ans)
    				check();
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    CodeForces 7B
    CodeForces 4D
    离散化
    线段树入门
    洛谷 P3951 小凯的疑惑(赛瓦维斯特定理)
    Codeforces 1295D Same GCDs (欧拉函数)
    Codeforces 1295C Obtain The String (二分)
    Codeforces 1295B Infinite Prefixes
    Codeforces 1295A Display The Number(思维)
    Codeforces 1294F Three Paths on a Tree(树的直径,思维)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8573036.html
Copyright © 2011-2022 走看看