2021年度训练联盟热身训练赛第七场 Problem K: Knightly Knowledge(离散化)

链接:https://ac.nowcoder.com/acm/problem/221163
来源:牛客网

示例1

输入

复制

2 3
0 5
5 0
0 1
0 3
3 0

输出

复制

0 0
3

示例2

输入

复制

6 5
-6 0
-4 0
-3 0
-4 -2
-3 -2
-2 -3
-6 -1
-4 -1
-3 -1
-5 -3
0 -3

输出

复制

-6 -3
3

示例3

输入

复制

1 2
0 0
1 0
0 1

输出

复制

0 0
2

upd:这题没数据QAQ所以下面代码只过了样例
大意就是给一些church和一些monument的坐标,一个church是mighty的当且仅当起所在的行有两个以上的monument/列有两个以上的monument。现在可以在任何地方(包括已经有monument或者church的位置)选择一处建一个monument,问在哪里建可以使新增加的mighty church最多。

首先看到坐标范围要离散化,然后直接暴力模拟即可。先找出每行每列的unmighty church的数量(通过每行/每列的church数量减去每行/每列的mighty church数量)以及求出离散化后每个church是否为unmighty church,然后遍历所有可能的选点坐标更新最大值即可。

注意特判m或者c为0的情况,不然会收获无数个段错误

看别人写的发现好多都用了unordered_map,我是废物

#include <bits/stdc++.h>
#define MAX 40005//随便开的大一点
using namespace std;
int m, c;
struct monument {
	int x, y;
} mon[1005];
struct church {
	int x, y;
} chu[1005];
vector<int> v, monpos;
//以下的位置都是离散化后的位置
int hmx[MAX], hmy[MAX];//hmx[i]这一行monument的数量
int cx[MAX], cy[MAX];//cx[i]代表i这一行的church的数量
int cmx[MAX], cmy[MAX];//cmx[i]代表i这一行的mighty church的数量
int umcx[MAX];//ucmx[i]代表i这一行的un mighty church的数量
int umcy[MAX];
bool umcxy[MAX][MAX];//标记x,y是否为un mighty church
int px, py, maxx = 0;
bool check(int id) {
	if(hmx[chu[id].x] >= 2 || hmy[chu[id].y] >= 2) return 1;
	return 0;
}
int main() { 
	cin >> m >> c;
	for(int i = 1; i <= m; i++){
		int x, y;
		cin >> x >> y;
		v.push_back(x);
		v.push_back(y);
		mon[i].x = x;
		mon[i].y = y;
		monpos.push_back(x);//每个monument涉及的行
		monpos.push_back(y);
 	}
 	for(int i = 1; i <= c; i++){
		int x, y;
		cin >> x >> y;
		v.push_back(x);
		v.push_back(y);
		chu[i].x = x;
		chu[i].y = y;
 	}
 	if(m == 0 || c == 0) {
 		cout << 0 << " " << 0 << endl;
 		cout << 0;
 		return 0;
 	}
 	sort(v.begin(), v.end());
 	vector<int>::iterator it = unique(v.begin(), v.end());
 	v.erase(it, v.end());
 	sort(monpos.begin(), monpos.end());
 	vector<int>::iterator it1 = unique(monpos.begin(), monpos.end());
 	monpos.erase(it1, monpos.end());
 	for(int i = 0; i < monpos.size(); i++) {
 		monpos[i] = lower_bound(v.begin(), v.end(), monpos[i]) - v.begin();
 	}
 	for(int i = 1; i <= m; i++){
		mon[i].x = lower_bound(v.begin(), v.end(), mon[i].x) - v.begin();
		mon[i].y = lower_bound(v.begin(), v.end(), mon[i].y) - v.begin();
		hmx[mon[i].x]++;
		hmy[mon[i].y]++;
 	}
 	for(int i = 1; i <= c; i++){
		chu[i].x = lower_bound(v.begin(), v.end(), chu[i].x) - v.begin();
		chu[i].y = lower_bound(v.begin(), v.end(), chu[i].y) - v.begin();
		cx[chu[i].x]++;
		cy[chu[i].y]++;
 	}
 	//现在要求umcx, umcy这两个数组
 	//不妨先求出来cmx, cmy
 	for(int i = 1; i <= c; i++) {
 		if(check(i)) {//判断它所在的行 / 列的monument的数量是否大于等于2
 			cmx[chu[i].x]++;
 			cmy[chu[i].y]++;
 		}
 	}
 	for(int i = 0; i <= 4000; i++) {
 		umcx[i] = cx[i] - cmx[i];
 		umcy[i] = cy[i] - cmy[i];
 	}
 	for(int i = 1; i <= c; i++) {
 		if(!check(i)) umcxy[chu[i].x][chu[i].y] = 1;
 	}
 	for(int i = 0; i < monpos.size(); i++) {//建造位置只可能选在所在行/列有monument的位置
 		for(int j = 0; j < monpos.size(); j++) {
 			int x = monpos[i], y = monpos[j];//遍历位置
 			int tmp = 0;
 			if(hmx[x]) {
 				tmp += umcx[x];//这个位置建造monument后这一行增加的mighty church数量
 			}
 			if(hmy[y]) {
 				tmp += umcy[y];
 			}
 			if(umcxy[x][y]) tmp--;//减去重复加的
 			if(tmp > maxx) {
 				maxx = tmp;
 				px = x, py = y;
 			}
 		}
 	}
 	px = v[px], py = v[py];
 	cout << px << " " << py << endl;
 	cout << maxx;
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/14726510.html