首页 > 其他分享 >CF15D-Map题解

CF15D-Map题解

时间:2023-03-01 16:11:06浏览次数:54  
标签:Map CF15D int 题解 back st 区域 1010 1001

题目传送门

题意:有一个 \(n\times m\) 的矩阵,每个格子有一个权值。每次操作会选择一个 \(x\times y\) 的矩形区域,花费为“每个位置的权值减去最小权值”之和,区域之间不能重叠。每次会选择花费最小的区间,如果有重复,则优先选上面的,再优先选左边的。输出每次的区域和花费。

显然选区域不会影响其他区域的花费,只会影响其他区域是否可选。思考可以发现,选择一个左上角为 \((a,b)\) 的区域,会导致左上角在 \((a-x+1\sim a+x-1,b-y+1\sim b+y-1)\) 的所有区域不可选。于是每次操作找到当前能选的最优区域,更改其他区域即可。

具体实现上,要用横竖两遍滑动窗口求出每个区域的最小值,再用二维前缀和求出每个区域的权值和,则该区域的花费为权值和减去 \(x\times y\) 倍最小值。

统计答案时,由于常数要求比较严格,需要预先对所有区域进行从优到劣的排序,每次看一个区域是否可选,如果可选就更新,否则到下一个。

对于判断是否可选,可以使用二维树状数组维护,也可以暴力更新。对于暴力更新的复杂度证明:首先发现选的区域个数不会超过 \(\frac{n\cdot m}{x\cdot y}\),而每次暴力更新的复杂度为 \(4xy\),所以更新的总复杂度为 \(4nm\)。

暴力更新 By cxm1024

#include<bits/stdc++.h>
using namespace std;
#define int long long
int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=(ch=='-'?-1:f),ch=getchar();
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x*f;
}
int a[1010][1010],s[1010][1010],t[1010][1010],sum[1010][1010];
bool vis[1010][1010];
signed main() {
	int n=read(),m=read(),x=read(),y=read();
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=m;j++) {
			a[i][j]=read();
			sum[i][j]=sum[i][j-1]+a[i][j];
		}
		deque<pair<int,int> > q;
		for(int j=0;j<y;j++) {
			while(!q.empty()&&q.back().second>=a[i][j])
				q.pop_back();
			q.push_back({j,a[i][j]});
		}
		for(int j=y;j<=m;j++) {
			if(!q.empty()&&q.front().first==j-y)
				q.pop_front();
			while(!q.empty()&&q.back().second>=a[i][j])
				q.pop_back();
			q.push_back({j,a[i][j]});
			s[i][j-y+1]=q.front().second;
		}
	}
	for(int j=1;j<=m-y+1;j++) {
		deque<pair<int,int> > q;
		for(int i=0;i<x;i++) {
			while(!q.empty()&&q.back().second>=s[i][j])
				q.pop_back();
			q.push_back({i,s[i][j]});
		}
		for(int i=x;i<=n;i++) {
			if(!q.empty()&&q.front().first==i-x)
				q.pop_front();
			while(!q.empty()&&q.back().second>=s[i][j])
				q.pop_back();
			q.push_back({i,s[i][j]});
			t[i-x+1][j]=q.front().second;
		}
	}
	for(int j=1;j<=m;j++)
		for(int i=1;i<=n;i++)
			sum[i][j]+=sum[i-1][j];
	vector<pair<int,pair<int,int> > > v;
	for(int i=1;i<=n-x+1;i++)
		for(int j=1;j<=m-y+1;j++) {
			int res=sum[i+x-1][j+y-1];
			res-=sum[i+x-1][j-1]+sum[i-1][j+y-1];
			res+=sum[i-1][j-1];
			v.push_back({res-t[i][j]*x*y,{i,j}});
		}
	sort(v.begin(),v.end());
	vector<pair<int,pair<int,int> > > ans;
	for(auto [tmp,pos]:v) {
		auto [i,j]=pos;
		if(vis[i][j]) continue;
		ans.push_back({tmp,pos});
		for(int di=-x+1;di<=x-1;di++)
			for(int dj=-y+1;dj<=y-1;dj++)
				if(i+di>0&&j+dj>0) vis[i+di][j+dj]=1;
	}
	printf("%lu\n",ans.size());
	for(auto [tmp,pos]:ans)
		printf("%lld %lld %lld\n",pos.first,pos.second,tmp);
	return 0;
}

二维树状数组 By vepifanov

int n;
int m;
int f[1001][1001];
int ww[1001][1001], w[1001][1001], g[1001][1001];
long long s[1001][1001];
ii st[1001];

vector<pair<long long, pair<int, int> > > all;
vector<pair<pair<int, int>, long long > > res;

int add (int x, int y) {
	for (int p = x; p <= n; p |= (p + 1))
		for (int q = y; q <= m; q |= (q + 1))
			f[p][q]++;
}

int get (int x, int y) {
	int s = 0;
	for (int p = x; p > 0; p = (p & (p + 1)) - 1)
		for (int q = y; q > 0; q = (q & (q + 1)) - 1)
			s += f[p][q];
	return s;
}

int main() {
	int a, b;
	scanf ("%d%d%d%d", &n, &m, &a, &b);
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			scanf ("%d", &g[i][j]);
	memset (s, 0, sizeof (s));
	for (int i = n - 1; i >= 0; i--)
		for (int j = m - 1; j >= 0; j--)
			s[i][j] = s[i + 1][j] + s[i][j + 1] - s[i + 1][j + 1] + g[i][j];
	for (int i = 0; i < n; i++) {
		int r = 0, l = 0;
		for (int j = 0; j < m; j++) {
			while (l < r && st[l].second + b <= j) l++;
			while (r > l && st[r - 1].first > g[i][j]) r--;
			st[r++] = make_pair (g[i][j], j);
			if (j - b + 1 >= 0) ww[i][j - b + 1] = st[l].first;
		}
	}

	for (int j = 0; j + b <= m; j++) {
		int r = 0, l = 0;
		for (int i = 0; i < n; i++) {
			while (l < r && st[l].second + a <= i) l++;
			while (r > l && st[r - 1].first > ww[i][j]) r--;
			st[r++] = make_pair (ww[i][j], i);
			if (i - a + 1 >= 0) w[i - a + 1][j] = st[l].first;
		}
	}

	for (int i = 0; i + a <= n; i++)
		for (int j = 0; j + b <= m; j++) {
			long long cur = s[i][j] - s[i + a][j] - s[i][j + b] + s[i + a][j + b];
			cur -= (long long)w[i][j] * a * b;
			all.push_back (make_pair (cur, make_pair (i, j)));
		}
	sort (all.begin (), all.end ());
	for (int i = 0; i < all.size (); i++) {
		long long q = all[i].first;
		int x = all[i].second.first;
		int y = all[i].second.second;
		if (get (x + a, y + b) - get (max (x - a + 1, 0), y + b) - get (x + a, max (y - b + 1, 0)) + get (max (x - a + 1, 0), max (y - b + 1, 0)) == 0) {
			res.push_back (make_pair (make_pair (x, y), q));
			add (x + 1, y + 1);
		}
	}
	printf ("%d\n", res.size ());
	for (int i = 0; i < res.size (); i++)
		printf ("%d %d %I64d\n", res[i].first.first + 1, res[i].first.second + 1, res[i].second);
	return 0;
}

标签:Map,CF15D,int,题解,back,st,区域,1010,1001
From: https://www.cnblogs.com/cxm1024/p/17168408.html

相关文章

  • CF杂题题解
    129B.StudentsandShoelaces题意:一个\(n\)个点\(m\)条边的无向图,每一轮删去所有度数为\(1\)的点,问删几轮停止。暴力模拟每一轮即可,每次删点更新邻居度数。{%......
  • CSP-J2022-C-逻辑表达式题解
    题意:给你一个由0、1、&、|、(、)组成的字符串,保证是一个合法的逻辑表达式。其中括号优先级最高,与运算优先级高于或运算,同级之间从左到右算。定义一次短路为,或运算的左边......
  • Gym100078H-History-of-Football题解
    题目传送门题意:有\(n\)支球队,每两支球队之间都会进行一场较量,赢者积\(3\)分,输者积\(0\)分,如果平局则各积\(1\)分。给出每支球队的最终积分,求方案数。\(n\le8\)......
  • Gym100753D-Carpets题解
    题目传送门题意:有一个\(H\timesW\)的地板和\(n\)个矩形地毯,问是否能不重不漏地填满地板。\(H,W\le100,n\le7\)。考虑朴素的搜索,每次考虑最左上角的没填的位置,枚......
  • Gym100825C-KenKen-You-Do-It题解
    题目传送门题意:在一个矩阵上选中了若干个格子,保证连通。你需要在这些格子中填数,使得:每行每列不能重复,且这些数进行给定运算(可以认为只有加法和乘法)的结果为给定的数值。......
  • Gym100959I-Robots题解
    题意:平面直角坐标系上有\(n\)个机器人,每个机器人有一个上下左右之一的方向,初始所有机器人静止。在第\(0\)秒,你让第一个机器人开始朝它的方向移动,速度为每秒一个单位。......
  • Gym101252B-Kakuro题解
    题目传送门题意:有一个矩阵,每个格子为黑色或白色。你需要向白色格子中填\(1\sim9\)的整整睡。从某一个黑色格子的右侧往右连续的一段极长的白色格子被称为一个run,往下......
  • C#、IIS获取时间带星期或日期问题解决
    ,获取时间老是带星期,如:2018-8-8星期日12:00:00,造成写入数据库时无法识别为时间格式报错。试了修改区域语言和修改指定注册表均无效。   解决方法一:在代码里处理时......
  • hashmap深入理解
    1.Map:地图* 1.概念:Map:就是用来装键值对集合的容器* 2.作用:* 解决了需要成对出现的这种关系结构* 键(key): 本质就是一个数据 值(value): 本质也是......
  • 【读书笔记&个人心得】第8章:Map
    Map一种元素对(pair)的无序集合,给定key,对应的value可以迅速定位,这个结构也称为关联数组或字典(如需要有序请使用结构体)给定key,对应的value可以迅速定位声明、初......