A. 設置營地#
有 3 種人需要住帳篷,分別有 ,, 個,第一種人是小波奇只願意自己住,第二種人是喜多一定要和另外 2 個人一起住,第三種人無所謂。每個帳篷最多住 3 個人,最少需要幾個帳篷?
小波奇自己住,喜多盡可能內部配隊,第三種人填補喜多的空缺,然後除 3 上取整。
B. 煙火#
有兩種煙火,分別在 和 時刻綻放,每次綻放持續 個單位時間,即分別在 和 時刻是綻放的。對所有時間點,求最大同時有多少個煙火綻放?
顯然,看一下第 時刻有多少個綻放即可,答案是 。
C. 左右房子#
有一條街有 個住戶,被一條路劃分成左右兩邊,每個住戶有一個住在左邊或右邊的意願 。現在,你要安排這條路的位置,使得左右兩邊都必須至少有住戶數除 2 上取整個人滿意,並且最小化其距離中點的距離,並且最小化道路坐標。
雖然條件很多,但是只需要從左到右枚舉道路放在哪即可,前後記一下前綴和,即可快速判斷合法性。
D. 天使貓頭鷹#
有一排長度為 的隊列,你現在站在隊列最右邊(坐標 )。假設你當前在位置 ,你每次可以往左邊跳到位置 ,花費代價 。你現在目標跳到小於等於 的某個位置,問最小代價。
原問題相當於每個位置選一個代價 或 花費,因為每個位置都只會從中選擇其一計算一次,並且最後一次花費的是 ,就能構造出一個合法的跳躍方案。注意,你需要枚舉最後一次的落點是在 中的某處,因為可能存在 很小 很大的情況。
E. 二分搜尋#
給你一個亂序的長度為 的排列,你可以最多 2 次,任意交換 2 個位置,使得對這個排列運行二分查找能找到答案。
乍一看你似乎要構造一個長度為 的序列來讓二分查找正確運行,但其實這就想歪了。可以發現,雖然二分的過程是亂的,但是確實實打實的在縮減目標區間到唯一一個。我們其實只需要讓它隨便運行,然後把答案放到隨便運行的目標位置上即可。
我們在二分的過程中標記一下訪問過哪些位置,那麼剩下的位置都可以隨意交換,最後找一個沒動過的位置換一下即可。注意,在隨便二分的過程中,因為可能半路就找到了答案,這時候需要額外花費一次操作,把答案換到一個別的地方。
反正大概是這麼個意思,隨便亂寫了一通,加了點 assert
,但是能過。
F. 基里爾和蘑菇#
給了你 個蘑菇,每個蘑菇有一個權值 。你可以從中選出 個蘑菇,權值是選出的蘑菇的權值最小值乘 。還有一個限制是,有一個排列 ,若你選擇的 個蘑菇,則這些 蘑菇的權值清空,無法選擇。求最大權值的前提下,最小選擇個數。
從 到 (雖然只能大概到一半)枚舉選了幾個蘑菇,維護剩餘蘑菇的前 大,然後清除一下對應的蘑菇。
大概感覺能直接搞個堆就行,但是不想動腦直接貼了個樹狀數組維護第 大。
G. 煮粥和粥#
有 個人排成一隊吃飯,有一堆它們在隊列裡排序的規則,問前 時刻內能否每人吃過一次,或者報告不行。
沒寫,大概搞個什麼數據結構維護弄一弄,感覺一堆細節不想寫。
H. GCD 更大#
給你一個大小為 的數組,你現在要將他們分成兩塊,且每塊至少有 2 個元素,第一塊求他們的 ,第二塊求他們的 加上參數 。求是否存在一種分割方案,使得第一塊的權值嚴格大於第二塊。
顯然,第一塊的 的數只需要 2 個就行了,因為數越多 越小;同樣, 也是數越多越小,但是是符合目標的。
那麼我可以直接枚舉 ,然後怎麼判一判就行了,然後就沒寫也沒細想了,應該差不多能做。
代碼#
A. 設置營地#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
int n, a[maxn];
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int cnt = a;
cnt += b / 3;
b %= 3;
if (b > 0 && b + c < 3) {
puts("-1");
continue;
} else {
if (b > 0) {
c -= 3 - b;
cnt++;
}
cnt += (c + 2) / 3;
printf("%d\n", cnt);
}
}
return 0;
}
B. 煙火#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
long long a, b, m;
scanf("%lld%lld%lld", &a, &b, &m);
long long ans = 2 + m / a + m / b;
printf("%lld\n", ans);
}
return 0;
}
C. 左右房子#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
int n, pre[maxn], suf[maxn];
char buf[maxn];
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%s", &n, buf + 1);
pre[0] = 0; suf[n + 1] = 0;
for (int i = 1; i <= n; i++) {
pre[i] = pre[i - 1] + (buf[i] == '0');
}
for (int i = n; i >= 1; i--) {
suf[i] = suf[i + 1] + (buf[i] == '1');
}
pre[n + 1] = pre[n]; suf[0] = suf[1];
auto check = [&](int p) {
int l = pre[p];
int r = suf[p + 1];
return l >= (p + 1) / 2 && r >= (n - p + 1) / 2;
};
int ans = -1;
for (int i = 0; i <= n; i++) {
if (check(i)) {
if (ans == -1 || abs(n - ans - ans) > abs(n - i - i)) {
ans = i;
}
}
}
assert(ans != -1);
printf("%d\n", ans);
}
return 0;
}
D. 天使貓頭鷹#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
int n, m, a[maxn], b[maxn];
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; i++) {
scanf("%d", b + i);
}
long long ans = 0, mn = a[m], sum = 0;
for (int i = n; i > m; i--) {
ans += min(a[i], b[i]);
}
for (int i = m; i >= 1; i--) {
mn = min(mn, a[i] + sum);
sum += b[i];
}
printf("%lld\n", ans + mn);
}
return 0;
}
E. 二分搜尋#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
int n, x, a[maxn];
void check() {
// for (int i = 1; i <= n; i++) {
// printf("%d%c", a[i], " \n"[i == n]);
// }
int l = 1, r = n + 1;
while (r - l > 1) {
int m = (l + r) / 2;
if (a[m] <= x) {
l = m;
} else {
r = m;
}
}
// printf(": %d %d\n", l, a[l]);
assert(r - l == 1 && a[l] == x);
}
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &x);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
vector<pair<int,int>> ans;
int l = 1, r = n + 1;
vector<int> visited(n + 1, 0);
while (r - l > 1) {
int m = (l + r) / 2;
if (a[m] == x && r - l > 1) {
int found = -1;
for (int i = 1; found == -1 && i <= n; i++) {
if (!visited[i]) found = i;
}
assert(found != -1);
ans.push_back({ m, found });
swap(a[m], a[found]);
}
visited[m] = 1;
if (a[m] <= x) {
l = m;
} else {
r = m;
}
}
if (a[l] != x) {
int found = -1;
for (int i = 1; found == -1 && i <= n; i++) {
if (a[i] == x) found = i;
}
assert(found != -1 && !visited[found]);
visited[found] = 1;
ans.push_back({ found, l });
swap(a[found], a[l]);
}
printf("%d\n", (int) ans.size());
for (auto& p: ans) {
printf("%d %d\n", p.first, p.second);
}
check();
}
return 0;
}
F. 基里爾和蘑菇#
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <utility>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int inf = 1e9 + 7;
const int maxn = 300000 + 5;
struct BIT {
static const int R = 1 << 21;
int a[R];
inline int lowbit(int x) { return x & -x; }
void insert(int i, int v) {
for (; i < R; i += lowbit(i)) a[i] += v;
}
void clear(int i) {
for (; i < R; i += lowbit(i)) a[i] = 0;
}
int findx(int p, int rk) {
// if (p > R) return -1;
if (p & 1) {
// if (p + (a[p] < rk) > R) return -1;
return p + (a[p] < rk);
} else {
if (rk > a[p]) return findx(p + lowbit(p) / 2, rk - a[p]);
else return findx(p - lowbit(p) / 2, rk);
}
}
int findx(int rk) {
return findx(R >> 1, rk);
}
} f;
int n, a[maxn], p[maxn];
int main() {
#ifdef DEBUG
freopen("../assets/in.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
vector<int> lsh;
auto gid = [&](int x) -> int {
return int(lsh.end() - lower_bound(lsh.begin(), lsh.end(), x));
};
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
lsh.push_back(a[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", p + i);
}
sort(lsh.begin(), lsh.end());
lsh.resize(unique(lsh.begin(), lsh.end()) - lsh.begin());
for (int i = 1; i <= n; i++) {
f.insert(gid(a[i]), 1);
}
long long ans = 0;
int cnt = 0;
for (int i = 1; i + i - 1 <= n; i++) {
int id = f.findx(i);
int val = lsh[lsh.size() - id];
// printf("Find: %d %d\n", id, val);
if (1ll * val * i > ans) {
ans = 1ll * val * i;
cnt = i;
}
// 刪除
f.insert(gid(a[p[i]]), -1);
}
printf("%lld %d\n", ans, cnt);
for (int i = 1; i <= n; i++) f.clear(gid(a[i]));
}
return 0;
}