牛客 周赛109 20250924

牛客 周赛109 20250924

https://ac.nowcoder.com/acm/contest/116945

A:
题目大意:

给定两个坐标,判断和原点一起能否构成一个直角三角形

void solve(){
	double x, y, u, v;
	cin >> x >> y >> u >> v;
	double L[] = {sqrt(x * x + y * y), sqrt(u * u + v * v), sqrt((x - u) * (x - u) + (y - v) * (y - v))};
	sort(L, L + 3);
	if (L[0] + L[1] <= L[2]) cout << "No";
	else cout << "Yes";
}

签到

B:
题目大意:

image-20250923150820760

void solve(){
	int n;
	cin >> n;
	vector<double> x(n), y(n);
	for (int i = 0; i < n; i ++)
		cin >> x[i] >> y[i];
		
	auto check = [&](int i, int j){
		double dx = x[i] - x[j], dy = y[i] - y[j];
		return abs(sqrt(dx * dx + dy * dy) - 1) < 0.000001;
	};
		
	int cnt = 0;
	for (int i = 0; i < n; i ++){
		for (int j = i + 1; j < n; j ++){
			if (check(i, j)) cnt ++; 
		}
	}
	cout << cnt ;
}

\(O(n^2)\) 的暴力

C:
题目大意:

image-20250923150907951

void solve(){
	pair<int, int> p1, p2, p3;
	cin >> p1.first >> p1.second >> p2.first >> p2.second;
	
	if (p1.first == p2.first || p1.second == p2.second){
		if (p1.first == p2.first){
			p3.second = min(p1.second, p2.second);
			p3.first = p1.first - 2;
		}else{
			p3.first = min(p1.first, p2.first);
			p3.second = p1.second - 2;
		}
		cout << p3.first << ' ' << p3.second; 
		return ;
	}
	
	if (p1.second < p2.second) swap(p1, p2);
	p3.first = p1.first;
	p3.second = p2.second;
	int dx = p2.first - p3.first;
	int dy = p1.second - p2.second;
	if (dx & 1 && dy & 1) p3.first -= dx;
	cout << p3.first << ' ' << p3.second; 
	
}

先构造出以 \(AB\) 为斜边的一个直角三角形,然后判断两条直角边是否都为奇数

如果全为奇数,那么面积存在小数,所以令任意一条直角边变为原来的两倍,构造满足题意

D:
题目大意:

image-20250923151146279

int dx[] = {1, 2, -1, -2};
int dy[] = {2, -2 , 1, -1};

void solve(){
	int n;
	cin >> n;
	vector<pair<int, int>> p(n);
	for (int i = 0; i < n; i ++)
		cin >> p[i].first >> p[i].second;
	sort(p.begin(), p.end());
	map<pair<int, int>, int> mp;
	for (int i = 0; i < n; i ++){
		int x = p[i].first, y = p[i].second;
		for (int u = 0; u < 4 ; u ++){
			for (int v = 0; v < 4; v ++){
				if (abs(dx[u]) == abs(dy[v])) continue;
				int tx = x + dx[u], ty = y + dy[v];
				if (tx <= 0 || ty <= 0) continue;
				mp[{tx, ty}] ++;
			}
		}
	}
	pair<int, int> ans = {0, 0};
	int mx = 0;
	for (auto [k ,v] : mp){
		if (mx < v && lower_bound(p.begin(), p.end(), k) != p.end()){
			mx = v;
			ans = k;
		}
	}
	cout << ans.first << ' ' << ans.second;
}

考虑用 map 记录所有可以威胁到兵的位置,至多存在 \(8n = 1.6e6\) 个,存入空间复杂度可以接受

最后枚举所有记录的位置,得到最大值答案

E:
题目大意:

image-20250923151817949

void solve(){
	int n;
	cin >> n;
	vector<pair<int, int>> p(n);
	for (int i = 0; i < n; i ++)
		cin >> p[i].first >> p[i].second;
	sort(p.begin(), p.end());
	map<int, set<int>> mp;
	for (int i = 0; i < n; i ++)
		mp[p[i].first].insert(p[i].second);
	int ans = 0;
	for (auto it = mp.begin(); next(it, 1) != mp.end(); it ++){
		auto st1 = (*it).second, st2 = (*next(it, 1)).second;
		if ((*it).first != (*next(it, 1)).first - 1) continue;
		int cnt = 0;
		for (auto i : st1){
			if (st2.count(i)) cnt ++;
		}
		ans += cnt * (cnt - 1) / 2;
	}

	mp.clear();
	for (int i = 0; i < n; i ++)
		mp[p[i].second].insert(p[i].first);
	for (auto it = mp.begin(); next(it, 1) != mp.end(); it ++){
		auto st1 = (*it).second, st2 = (*next(it, 1)).second;
		if ((*it).first != (*next(it, 1)).first - 1) continue;
		int cnt = 0;
		for (auto i : st1){
			if (st2.count(i)){
				cnt ++;
				if (st1.count(i - 1) && st2.count(i - 1)) ans --;
			}
		}
		ans += cnt * (cnt - 1) / 2;
	}
	cout << ans ;
}

对点进行两次排序,第一次按照横坐标从小到大排序,把点按照横坐标存进不同的 set 中,然后枚举 map 中的 set

暴力计算相邻的横坐标相差一的 set 中相同的纵坐标数量,排列组合计算在横坐标相差一下可以构造的矩形数量

同样的对纵坐标排序后相似计算,注意还需要减去长宽都为 \(1\) 的矩形重复的贡献

for (auto i : st1){
	if (st2.count(i)){
		cnt ++;
		if (st1.count(i - 1) && st2.count(i - 1)) ans --;
	}
}

F:
题目大意:

image-20250923152235422

const int N = 2e5 + 10;

struct Q{
	int k1, k2, idx;
};

int s[N];

int lowbit(int x){
	return x&-x;
}

void change(int x, int k){
	while (x < N){
		s[x] += k;
		x += lowbit(x);
	}
}

int query(int x){
	int res = 0;
	while (x){
		res += s[x];
		x -= lowbit(x);
	}
	return res;
}

void solve(){
	int n, m;
	cin >> n >> m;
	vector<pair<int, int>> p(n);
	for (int i = 0; i < n; i ++)
		cin >> p[i].first >> p[i].second;	
	vector<Q> q(m);
	for (int i = 0; i < m; i ++){
		cin >> q[i].k1 >> q[i].k2;
		q[i].idx = i;
	}
	
	set<int> st;
	map<int, int> mp;
	int idx = 0;
	
	for (int i = 0; i < n; i ++){
		int x = p[i].first, y = p[i].second;
		p[i].first = x - y;
		p[i].second = x + y;
		st.insert(p[i].second);
	}
	for (int i = 0; i < m; i ++){
		q[i].k1 *= -1;
		st.insert(q[i].k2);
	}
		
	for (auto i : st) mp[i] = ++ idx;
	for (int i = 0; i < n; i ++){
		p[i].second = mp[p[i].second];
		change(p[i].second, 1);
	}
	for (int i = 0; i < m; i ++) q[i].k2 = mp[q[i].k2];
	
	auto cmp = [&](Q x, Q y){
		return x.k1 < y.k1;
	};
	
	sort(p.begin(), p.end());
	sort(q.begin(), q.end(), cmp);
	
	int i = 0, j = 0;
	vector<int> ans(m);
	while (i < m){
		while (j < n && p[j].first <= q[i].k1){
			change(p[j].second, -1);
			j ++;
		}
		ans[q[i].idx] = query(q[i].k2 - 1);
		i ++;
	}
	for (auto i : ans) cout << i << '\n';
	
}

给定的点需要满足下面的约束:

\[y - x < k_1\\ y + x < k_2 \]

换算到切比雪夫坐标下,令 \(X = x -y,Y=x + y\) ,约束为 \(X > -k_1,Y<k_2\)

对询问和点集按照 \(X\) 从小到大排序后,离散化后树状数组查询对应 \(Y\) 满足的点的数量

while (i < m){//枚举询问
	while (j < n && p[j].first <= q[i].k1){//删去点集中不合法的点
		change(p[j].second, -1);
		j ++;
	}
	ans[q[i].idx] = query(q[i].k2 - 1);//处理询问
	i ++;
}

时间复杂度为 \(O(n\log n)\)

posted @ 2025-10-06 14:22  才瓯  阅读(8)  评论(0)    收藏  举报