A:三个数找中间大
void solve() {
vector<int> a(3);
rep(i, 0, 3) cin >> a[i];
sort(all(a));
cout << a[1] << endl;
}
B:问你字符串中最大的字母对应编号
void solve() {
int n; cin >> n;
string s; cin >> s;
char c = 'a';
for (auto x : s) c = max(c, x);
cout << c - 'a' + 1 << endl;
}
C:问你每个数与最大值的差, 最大值则与第二大的特判
void solve() {
int n; cin >> n;
int mx1 = -1e8, mx2 = -1e8;
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
if(a[i] > mx1) mx2 = mx1, mx1 = a[i];
else if(a[i] > mx2) mx2 = a[i];
}
for (int i = 1; i <= n; i ++ ) {
if(a[i] != mx1) cout << a[i] - mx1 << ' ';
else cout << mx1 - mx2 << ' ';
}
cout << endl;
}
D:问你当前这个数组是不是有谷
void solve() {
int n; cin >> n;
repn(i, 1, n) cin >> a[i];
bool fg = false;
for (int i = 2; i <= n; i ++ ) {
if(a[i] == a[i - 1]) continue;
if(fg) {
if(a[i] < a[i - 1]) {cout << "NO" << endl; return;}
}
if(a[i] > a[i - 1]) fg = true;
}
cout << "YES" << endl;
}
E:给你一个01串,你最多可以修改一个位置,将0->1, 1->0,问你最大的逆序对数量。
思路:先处理出原始的逆序对数量。然后分分别枚举每一个位置
1->0:ans减去后缀0的数量,加上前缀1的数量
0->1:ans加上后缀0的数量,减去前缀1的数量。
void solve() {
int n; cin >> n;
for (int i = 0; i <= n + 20; i ++ ) pre1[i] = pre0[i] = end0[i] = end1[i] = 0;
map<int, int> mp;
ll ans = 0;
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
mp[a[i]] ++;
if(a[i] == 0) ans += mp[1];
}
if(a[1] == 0) pre0[1] = 1;
else pre1[1] = 1;
for (int i = 2; i <= n; i ++ ) {
pre0[i] = pre0[i - 1] + (a[i] == 0);
pre1[i] = pre1[i - 1] + (a[i] == 1);
}
if(a[n] == 0) end0[n] = 1;
else end1[n] = 1;
for (int i = n - 1; i >= 0; i -- ) {
end0[i] = end0[i + 1] + (a[i] == 0);
end1[i] = end1[i + 1] + (a[i] == 1);
}
ll tmp = ans;
for (int i = 1; i <= n; i ++ ) {
if(a[i] == 1) {
ans = max(ans, tmp - end0[i + 1] + pre1[i - 1]);
}
else ans = max(ans, tmp + end0[i + 1] - pre1[i]);
//cout << ans << endl;
}
cout << ans << endl;
}
F:你有n个工作,每个工作对应ai的收益。你还有一个c和一个d,d是deadline。现在,完成了一个工作会有一个约束,即k天内无法再次做这个工作。现在问你d天内,我们是否可以最大化k,使得收益达到c。
思路:很明显的二分答案。我们可以二分这个答案k。贪心的考虑,我们每次肯定都是先做收益ai最大的工作。所以排个序,取模随便搞一搞就行了。注意一下define int long long
void solve() {
cin >> n >> c >> d;
for (int i = 1;i <= n; i++ ) cin >> a[i];
int sum = 0, mx = 0;
for (int i = 1; i <= n; i++ ) sum += a[i], mx = max(mx, a[i]);
if(mx * d < c) {cout << "Impossible" << endl; return;}
sort(a + 1, a + n + 1);
int l = 0, r = INF;
auto check = [&](int mid) {
int res = 0;
for (int i = n; i >= max(n - mid, 1ll); i --) res += a[i];
int sum = 0;
for (int i = n, j = d % (mid + 1); j >= 1 && i >= max(n - mid, 1ll); i --, j -- ) sum += a[i];
return d / (mid + 1) * res + sum >= c;
};
while(l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
if(r < INF) cout << r << endl;
else cout << "Infinity" << endl;
}
G:有一棵树,每条树边有一个权值w,问你从a走到b,是否能使得边的权值异或是0,但是中间你可以随便跳一次。也是在路上随便位移到另外一个点。
思路:从a开始不到b跑一边前缀异或值,放入set或者map。然后从b再出发随便跑一遍,记录异或值。如果异或值已经出现了,说明我们直接瞬移到这个点然后走回去就是0了。
vector<array<int, 2>> e[N];
int ans;
bool fg;
map<int, int> mp;
void solve() {
cin >> n >> a >> b;
mp.clear();
for (int i = 0; i <= n + 10; i ++ ) e[i].clear();
for (int i = 1; i < n; i ++ ) {
int a, b, c; cin >> a >> b >> c;
e[a].pb({b, c});
e[b].pb({a, c});
}
auto dfs = [&](auto&& self, int u, int fa, int cur) -> void {
mp[cur] = 1;
for (auto [to, v]: e[u]) {
if(to == fa) continue;
if(to == b) continue;
self(self, to, u, cur ^ v);
}
};
auto dfs2 = [&](auto&& self, int u, int fa, int cur) -> void {
for (auto [to, v] : e[u]) {
if(to == fa) continue;
self(self, to, u, cur ^ v);
if(fg) return ;
if(mp[cur ^ v]) {
fg = true;
cout << "YES" << endl;
}
}
};
dfs(dfs, a, 0, 0);
fg = false;
dfs2(dfs2, b, 0, 0);
if(!fg) {cout << "NO" << endl; return;};
}