C. Smilo and Minecraft R1700
题意:给定一个n*m的网格,每个网格里可以是空、石头和金子。要求通过爆炸来获得尽可能多的金子,规则如下:
1.只有空的地方可以安放爆炸点(题目保证至少有一个空格子)
2.爆炸后,x,y坐标距离爆炸点小于k的金子和石头全部消失
3.x或y坐标距离爆炸点等于k的网格中如果有金子,则你获得。
思路:
1.可以无限制安放zhayao,这是一个非常好的条件。或许我们可以找到一种方法,它不能最小化爆炸次数,但是对于任意情况一定可以满足最大化得到的金子。
2.注意到:如果我们第一个爆炸点选在(x, y),那么接下来爆炸点选在它的四周,一定不会有多余的金子被炸消失。
3.那么答案就显而易见了:只有第一个爆炸点可能导致金子被炸没,其余的金子一定可以被获取。
用二维前缀和统计矩形范围内可能被炸掉的最多金子。然后枚举第一次爆炸点。
二维前缀和:
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]
a[i][j] = s[i][j] + s[i - 1][j - 1] - s[i][j - 1] - s[i - 1][j]
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 200005
void solve() {
int n, m, k; cin>>n>>m>>k;
vector<string> a(n + 1);
for (int i = 1; i <= n; ++i) cin>>a[i];
vector<vector<int>> s(n + 1, vector<int>(m + 1, 0));
int broken = INT_MAX;
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] + (a[i][j - 1] == 'g');
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[i][j - 1] == '.') {
int L = max(1, j - k + 1), R = min(m, j + k - 1), U = max(1, i - k + 1), B = min(n, i + k - 1);
broken = min(broken, s[B][R] - s[U - 1][R] - s[B][L - 1] + s[U - 1][L - 1]);
}
}
}
int ans = s[n][m] - broken;
cout<<ans<<endl;
}
int main() {
int tt; cin>>tt;
while (tt--) solve();
return 0;
}

浙公网安备 33010602011771号