CF15D Map 题解

考虑到 n,m1000n, m \leq 1000,所以直接模拟是可行的。

一开始,预处理出以每个点为左上角的 a×ba \times b 的矩形的答案。矩形和显然可以二维前缀和,最小值可以 ST 表配合 multiset 做到一只 log\log,也可以单调队列把 log\log 优化掉。

每次选择最小的答案,把这个矩阵能影响的点删掉,循环做即可。

比较卡常,建议使用手写懒惰删除堆代替 multiset

#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
using namespace std;

const int N = 1005;

int n, m, a, b;

int c[N][N];
long long sum[N][N];

struct Node
{
	int x, y;
	long long w;
	Node(int _x, int _y, long long _w): x(_x), y(_y), w(_w){}
	Node() = default;
	bool operator<(const Node& xx) const
	{
		if (w != xx.w) return w > xx.w;
		if (x != xx.x) return x > xx.x;
		return y > xx.y;
	}
	bool operator==(const Node& g) const
	{
		return x == g.w && y == g.y && w == g.w;
	}
};

class Mymultiset
{
public:
	priority_queue<Node> q1, q2;
	void ins(Node x)
	{
		q1.push(x);
	}
	void del(Node x)
	{
		q2.push(x);
	}
	int sz()
	{
		return q1.size() - q2.size();
	}
	Node Top()
	{
		while (q2.size() && q1.top() == q2.top()) q1.pop(), q2.pop();
		return q1.top();
	}
	void Pop()
	{
		while (q2.size() && q1.top() == q2.top()) q1.pop(), q2.pop();
		q1.pop();
	}
};

Mymultiset mt;

int LG2[N];

class ST
{
public:
	int f[11][N];
	void Init(int *c)
	{
		memset(f, 0x3f, sizeof f);
		for (int i = 1; i <= m; i++) f[0][i] = c[i];
		for (int j = 1; j <= LG2[m]; j++)
		{
			for (int i = 1; i + (1 << j) - 1 <= m; i++)
			{
				f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
			}
		}
	}
	int query(int l, int r)
	{
		int p = LG2[r - l + 1];
		return min(f[p][l], f[p][r - (1 << p) + 1]);
	}
}s[N];

bool vis[N][N];

signed main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	for (int i = 2; i < N; i++) LG2[i] = LG2[i / 2] + 1;
	cin >> n >> m >> a >> b;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++) 
		{
			cin >> c[i][j];
			sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + c[i][j];
		}
		s[i].Init(c[i]);
	}
	vector<Node> res;
	for (int j = 1; j <= m - b + 1; j++)
	{
		multiset<int> sts;
		for (int i = 1; i <= a; i++) sts.insert(s[i].query(j, j + b - 1));
		for (int i = 1; i <= n - a + 1; i++)
		{
			long long su = sum[i + a - 1][j + b - 1] - sum[i + a - 1][j - 1] - sum[i - 1][j + b - 1] + sum[i - 1][j - 1];
			mt.ins(Node(i, j, su - 1LL * (*sts.begin()) * a * b));
			sts.erase(sts.find(s[i].query(j, j + b - 1)));
			if (i + a <= n) sts.insert(s[i + a].query(j, j + b - 1));
		}
	}
	while (mt.sz())
	{
		auto u = mt.Top();
		mt.Pop();
		if (vis[u.x][u.y]) continue;
		vis[u.x][u.y] = 1;
		res.emplace_back(u);
		for (int i = max(1, u.x - a + 1); i <= u.x + a - 1; i++)
		{
			for (int j = max(1, u.y - b + 1); j <= u.y + b - 1; j++) vis[i][j] = 1;
		}
	}
	cout << res.size() << "\n";
	for (auto &[x, y, z] : res)
	{
		cout << x << " " << y << " " << z << "\n";
	}
	return 0; 
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示