Description

给定一个网格,每个格子上有一个数字。一次操作可以将 \(r~\times~c\) 的一块矩形的数字减去 \(1\)。必须保证这个矩形中的数全部为正。每次操作的 \(r\) 和 \(c\) 必须保持不变。求最少操作次数

Input

第一行是两个整数 \(n,m\),代表格子行列数

下面 \(n\) 行 \(m\) 列描述这个格子

Output

一行一个数字代表答案

Hint

\(1~\leq~n,m~\leq~100\),数字和不超过 \(10^9\)

Solution

非常显然的想法是枚举 \(r,c\),然后暴力的判断是否合法。枚举 \(r,c\) 的复杂度是 \(O(n^2)\),暴力判断的复杂度为 \(O(n^2 \log^2 n)\),总复杂度 \(O(n^4 \log^2 n)\)。

然后发现这个题目的特殊性质:行列不相关。即无论列选择多大,行的最优解是不变的。列得选择同理。证明上,可以考虑数学归纳法。显然选取列为 \(1\) 时能算出行的最优解。当选取列为 \(k\) 时的最优解已经算出时,考虑计算选取列为 \(k + 1\) 时的最优解。我们发现如果列为 \(k + 1\) 时是合法的,那么列为 \(k\) 时一定是合法的。同时这个条件也是必要条件。所以我们可以按照列选择 \(1\) 时枚举出行的最优解,行选择 \(1\) 时枚举出列得最优解。即可得到答案。

考虑检验是否合法时,可以使用二维树状数组维护差分从而支持区间减法。总复杂度 \(O(n^3 \log^2n)\)。可以通过本题。事实上,由于另一个方位是 \(1\),所以可以直接维护一维树状数组做到 \(O(n^3 \log n)\)。然而要写两遍……

Code

#include <cstdio>
#include <cstring>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#define printtime()
#else
#include <ctime>
#define printtime() printf("Times used = %ld ms\n", clock())
#endif
#define ci const int
#define cl const long long typedef long long int ll; namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
} template <typename T>
inline void qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
} template <typename T>
inline void ReadDb(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
} namespace OPT {
char buf[120];
} template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
} const int maxn = 110; int n, m;
int MU[maxn][maxn], CU[maxn][maxn], tree[maxn][maxn]; inline int lowbit(ci x) {return x & -x;} int check(ci, ci);
void insert(ci, ci, ci);
int ask(ci, ci);
int query(ci, ci); int main() {
freopen("1.in", "r", stdin);
qr(n); qr(m);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) qr(MU[i][j]);
int r = n, c = m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) CU[i][j] = MU[i][j] - MU[i - 1][j] - MU[i][j - 1] + MU[i - 1][j - 1];
while (check(r, 1) == -1) --r;
while (check(1, c) == -1) --c;
int sum = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) sum += MU[i][j];
qw(sum / (r * c), '\n', true);
printtime();
} int check(ci x, ci y) {
int a = n - x + 1, b = m - y + 1, cnt = 0;
memset(tree, 0, sizeof tree);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
insert(i, j, CU[i][j]);
for (int i = 1; i <= a; ++i)
for (int j = 1; j <= b; ++j) {
int k = ask(i, j);
if (k < 0)
return -1;
cnt += k;
insert(i, j, -k); insert(i + x, j, k); insert(i, j + y, k); insert(i + x, j + y, -k);
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) if (ask(i, j) != 0)
return -1;
return cnt;
} void insert(ci x, ci y, ci v) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= m; j += lowbit(j))
tree[i][j] += v;
} int ask(ci x, ci y) {
return query(x, y) - query(x - 1, y) - query(x, y - 1) + query(x - 1, y - 1);
} int query(ci x, ci y) {
int _ret = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
_ret += tree[i][j];
return _ret;
}

【枚举&数据结构】【P2484】 [SDOI2011]打地鼠的更多相关文章

  1. 洛谷P2484 [SDOI2011]打地鼠

    P2484 [SDOI2011]打地鼠 题目描述 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多 ...

  2. Luogu P2484 [SDOI2011]打地鼠(模拟+前缀和)

    P2484 [SDOI2011]打地鼠 题意 题目描述 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地 ...

  3. P2484 [SDOI2011]打地鼠

    差分 代码: #include <bits/stdc++.h> using namespace std; #define INF 1999999999 ][],b[][],c[][]; i ...

  4. Bzoj 2241: [SDOI2011]打地鼠 暴力,枚举,贪心

    2241: [SDOI2011]打地鼠 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1022  Solved: 651[Submit][Status ...

  5. 【BZOJ2484】[SDOI2011]打地鼠(暴力)

    [BZOJ2484][SDOI2011]打地鼠(暴力) 题面 BZOJ 洛谷 题解 看到数据范围这题就应该是一个暴力题了. 先考虑假如我们知道了锤子的大小\(R*C\),那么显然只需要从左上角开始从左 ...

  6. BZOJ 2241: [SDOI2011]打地鼠 暴力

    2241: [SDOI2011]打地鼠 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pro ...

  7. [BZOJ 2241][SDOI2011]打地鼠(枚举+预处理)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2241 分析: 鉴于R,C的取值很小,于是可以人为枚举R和C的大小,然后判定这个规格的锤 ...

  8. 2241. [SDOI2011]打地鼠【暴力+剪枝】

    Description 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高. 游戏中的锤 ...

  9. BZOJ2241 [SDOI2011]打地鼠 【模拟】

    题目 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高. 游戏中的锤子每次只能打一只地 ...

随机推荐

  1. 无法连接 Plugins Market 失效的日子

    一.问题背景 不知道是什么原因,我的 Intellij 连接不上 Plugins Market,这时候我需要使用 @Data 注解来自动生成 Getter.Setter 方法.在添加了相应的依赖之后, ...

  2. 深入理解JavaScript函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数. arguments javascri ...

  3. oracle数据update后怎么恢复到以前的数据

    http://blog.csdn.net/itdada/article/details/52746392

  4. C++:友元

    前言:友元对于我来说一直是一个难点,最近看了一些有关友元的课程与博客,故在此将自己的学习收获做一个简单的总结 一.什么是友元 在C++的自定义类中,一个常规的成员函数声明往往意味着: • 该成员函数能 ...

  5. Sprint10

    进展:设置事件提醒部分已经完成,接下来是实现完成后在添加主界面显示已添加的事件及时间,并可设置可用与不可用.

  6. css3学习笔记三

    css3有些特殊的元素选择器这和jquery相似.效果图如下

  7. Ubuntu下ssh连接在服务端显示图形界面

    Ubuntu下ssh连接在服务端显示图形界面 step1 安装ssh服务 服务端安装运行ssh,在终端运行命令如下: sudo apt-get install openssh-server 在客户端安 ...

  8. 【贪心算法】POJ-1862 简单哈夫曼

    一.题目 Description Our chemical biologists have invented a new very useful form of life called stripie ...

  9. 网桥 以及 IEEE802.1D 生成树协议

    (一)网桥 网桥是一个layer 2设备,能够连接两个不同的网段. 如图

  10. THREE.JS(如何想场景中添加物体对象)

    这篇主要实现向模型对象中添加头像,并组成一个矩形 一.three.js是什么? 上篇说了点TWEEN这篇又来一根THREE是不是两兄弟啊?还真有点像,当想要做3D动画的时候,可能会考虑用TWEEN的动 ...