ABC257C —— 一题多解

传送门:$ \sum _{i = 1} ^{n} a_i $

题意:给一个实数x,体重小于x的判为小孩(0),大于x判为大人(1),问最多有多少个人能被正确的判为小孩/大人。

解法1

我们不妨枚举一下合适的x。
由于判定方法是 $ < x $ 或 $ > x $ ,所以只有两个数中间(.5)合适。
我们把体重与0/1捆绑在一起,然后按体重排序(注意体重相同的大人要排在小孩前面),再前后缀和处理(包括本身)。
前缀算前面有多少个0,后缀算后面有多少个1(因为小孩: $ < x $,大人: $ > x $)
最后枚举一遍,算前缀+后缀,取最大值即可。


为什么体重相同的大人要排在小孩前面?
因为这样就会从000000111111变成000111000111(仅举例),才能得到正确的结果9。

// 代码中,使用01反转的方式+pair的排序方法,使得相同体重的1在0前面。
#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <set>
#include <map>
#include <utility>
#include <queue>
#include <vector>
#include <bitset>
#include <stack>
#include <sstream>
#include <algorithm>

#define INF 1000000007
#define MOD 998244353

using namespace std;

#define maxn 200005

int L[maxn], R[maxn];
pair<int, int> P[maxn];

int main() {
	int n;
	string s;
	cin >> n >> s;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &P[i].first);
		P[i].second = '1' - s[i - 1]; // 01反转
	}
	sort(P + 1, P + n + 1); // 十年OI一场空,没有排序见祖宗。
	L[0] = 0;
	for (int i = 1; i <= n; i++) {
		L[i] = L[i - 1] + (P[i].second == 1);
	}
	R[n + 1] = 0;
	for (int i = n; i >= 1; i--) {
		R[i] = R[i + 1] + (P[i].second == 0);
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		ans = max(ans, L[i] + R[i]);
	}
	printf("%d", ans);
	return 0;
}

解法2

先统计出1有多少个(相当于 $ X=0 $ 时的 $ f(X) $ )
f = 0,遍历一遍:

  • 遇到0,f++
    • 遇到0时因为没有要舍弃的1,还能判对一个0,所以f++
  • 遇到1,f--
    • 遇到1时因为有要舍弃的1,还没有能判对的0,所以f--

每次操作完后更新一下f,全剧终…………………………?

#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <set>
#include <map>
#include <utility>
#include <queue>
#include <vector>
#include <bitset>
#include <stack>
#include <sstream>
#include <algorithm>

#define INF 1000000007
#define MOD 998244353

using namespace std;

#define maxn 200005

typedef struct {
	int weight, age;
} person;

bool operator <(person lhs, person rhs) {
	if (lhs.weight == rhs.weight) {
		return lhs.age > rhs.age; // 同样是反转的顺序,解释同解法1。
	} else {
		return lhs.weight < rhs.weight;
	}
}

person people[maxn];

int main() {
	int n;
	string s;
	cin >> n >> s;
	int ans = 0;
	int x = 0;
	for (int i = 0; i < n; i++) {
		scanf("%d", &people[i].weight);
		if (s[i] == '1') {
			people[i].age = 1;
			ans++;
			x++;
		} else {
			people[i].age = 0;
		}
	}
	sort(people, people + n); // 十年OI一场空,没有排序见祖宗。
	for (int i = 0; i < n; i++) {
		if (people[i].age == 0) {
			x++;
		} else {
			x--;
		}
		ans = max(ans, x);
	}
	printf("%d", ans);
	return 0;
}

解法3——不反转的解法

跟解法1类似。
这次,小孩在大人前面。
那相同体重的怎么办?答曰:跟上一个体重不同时再更新。
这样就能抛弃1了,注意最前面也得更新一次(抛弃0)。

#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <set>
#include <map>
#include <utility>
#include <queue>
#include <vector>
#include <bitset>
#include <stack>
#include <sstream>
#include <algorithm>

#define INF 1000000007
#define MOD 998244353

using namespace std;

#define maxn 200005

int L[maxn], R[maxn];
pair<int, int> P[maxn];

int main() {
	int n;
	string s;
	cin >> n >> s;
	for (int i = 0; i < n; i++) {
		scanf("%d", &P[i].first);
		P[i].second = s[i] - '0';
	}
	sort(P, P + n); // 十年OI一场空,没有排序见祖宗。
	L[0] = 0;
	for (int i = 0; i < n; i++) {
		L[i + 1] = L[i] + (P[i].second == 0); // i + 1!!!!!!
	}
	R[n] = 0;
	for (int i = n - 1; i >= 0; i--) {
		R[i] = R[i + 1] + (P[i].second == 1);
	}
	int ans = max(L[n], R[0]);
	for (int i = 1; i < n; i++) {
		if (P[i].first != P[i - 1].first) {
			ans = max(ans, L[i] + R[i]);
		}
	}
	printf("%d", ans);
	return 0;
}

再见!不求关注,推荐就好!反正不要白嫖!

posted @ 2022-06-27 11:01  A-Problem-Solver  阅读(65)  评论(0编辑  收藏  举报