专栏文章

题解:P4165 [SCOI2007] 组队

P4165题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@minduk85
此快照首次捕获于
2025/12/02 00:47
3 个月前
此快照最后确认于
2025/12/02 00:47
3 个月前
查看原文
~纪念模拟赛因狗屎搬题人开大数据未离散化导致的挂分~
~个人认为这题评紫是不是高了~

题意:

给出一些球员的身高和速度以及三个常数 A,B,CA,B,C,请你选出一些球员。设这些球员中身高最矮为 minhminh,速度最小为 minvminv,求最多选出多少名球员使得对于任意球员满足 A×(hminh)+B×(vminv)CA \times (h - minh) + B \times (v - minv) \le C

题解:

看见对于每个球员有两个信息,以及一条限制,想到一个类似于二维偏序的东西。
我们对于每个球员先以 hh 为第一关键字排序。
首先我们枚举可能作为最小身高的球员 ii
那么对于所有 jij \ge i,此时,可以保证选 jj 能让最小身高合法。
那么对于球员 jjA×(hjhi)+B×(vjminv)CA \times (h_j - h_i) + B \times (v_j - minv) \le C
我们把式子变换成关于未知数的,就有 minvvjCA×(hjhi)Bminv \ge v_j - \frac{C - A \times (h_j - h_i)}{B}
同时,对于每个球员 jj 我们要保证 minvvjminv \le v_j
所以,对于每个球员 jj,当且仅当 minvminv 满足 vjCA×(hjhi)Bminvvjv_j - \frac{C - A \times (h_j - h_i)}{B} \le minv \le v_jminvminv 合法。
因此我们可以把满足 vjCA×(hjhi)Bminvvjv_j - \frac{C - A \times (h_j - h_i)}{B} \le minv \le v_jminvminv 的答案加一表示这个区间内的 minvminv 可选的球员个数加一,这里可以使用差分维护。
最后把差分数组还原并且对于所有身高合法的球员看一下他作为身高最小者对应的答案有几个取最大值即可。

代码

码风丑陋的代码CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){
		if(ch == '-'){
			f = -1;
		}
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}
void write(int x){
	if(x < 0){
		putchar('-');
		x = -x;
	}
	if(x > 9){
		write(x / 10);
	}
	putchar(x % 10 + '0');
	return;
}
int N, m, A, B, C, ans, maxn, d[10005];
struct node{
	int h, v, cnt;
}t[10005], f[10005];
bool cmp(node x, node y){
	if(x.h == y.h){
		return x.v < y.v; 
	}
	return x.h < y.h;
}
signed main(){
	N = read(), A = read(), B = read(), C = read();
	for(int i = 1; i <= N; i++)
		t[i].h = read(), t[i].v = read(), t[i].cnt = 1;
	sort(t + 1, t + N + 1, cmp);
	for(int i = 1; i <= N; i++){//离散化 
		if(t[i].h == f[m].h && t[i].v == f[m].v)
			f[m].cnt++;
		else
			m++, f[m] = t[i];
	}
	for(int i = 1; i <= m; i++){//枚举身高最矮的球员 
		int minn = 1e18, maxn = 0;
		for(int j = i; j <= m; j++){//枚举所有身高合法的球员 
            if(A * (f[j].h - f[i].h) > C)//单论身高已经炸了的直接跳过 
                break;
            int minv = (B/*考虑到 B可能为 0 避免 RE,当 B为 0 时,minv 为任意非负数均合法*/ ? max(0ll, f[j].v - (C - A * (f[j].h - f[i].h)) / B) : 0);//表示最低合法最小速度
			d[minv] += f[j].cnt, d[f[j].v + 1] -= f[j].cnt;//表示速度在l-f[j].v之间的球员可以和j球员一队 
		}
		for(int j = 1; j <= 1e4; j++)
			d[j] += d[j - 1];//差分化为原数组 
		for(int j = i; j <= m; j++)
			ans = max(ans, d[f[j].v]);//统计答案 
		memset(d, 0, sizeof(d));//清空差分数组 
	}
	write(ans);
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...