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++
。
- 遇到0时因为没有要舍弃的1,还能判对一个0,所以
- 遇到1,
f--
。- 遇到1时因为有要舍弃的1,还没有能判对的0,所以
f--
。
- 遇到1时因为有要舍弃的1,还没有能判对的0,所以
每次操作完后更新一下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;
}
再见!不求关注,推荐就好!反正不要白嫖!