A. Arrow a Row
一個簡單的構造題,構造的思路是先把又側的連續>
放滿,再從左側逐個開始放,如果是>
就放一個長度為 5 的,如果是-
,可以一次性直接把連續的都放了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
string check(int n, vector<pii> op) {
string s(n + 1, '*');
for(auto [x, len] : op) {
s[x] = s[x + len - 1] = s[x + len - 2] = s[x + len - 3] = '>';
for(int i = x + 1; i <= x + len - 4; i ++)
s[i] = '-';
cout << s << "\n";
}
return s;
}
void solve() {
string s;
cin >> s;
int n = s.size() - 1;
if(s[0] != '>' or s[n] != '>' or s[n - 1] != '>' or s[n - 2] != '>'){
cout << "No\n";
return;
}
bool ok = false;
for(int i = 1; i <= n - 3; i ++) {
if(s[i] == '-') {
ok = true;
break;
}
}
if(ok == false){
cout << "No\n";
return;
}
vector<pii> op;
int lst = -1;
for(int i = n; i >= 0; i --){
if(s[i] == '>' and s[i - 1] == '>' and s[i - 2] == '>') {
op.emplace_back(i - 4, 5);
i = i - 2;
} else if(s[i] == '>' and s[i - 1] == '>') {
op.emplace_back(i - 3, 5);
lst = i - 2;
break;
} else if(s[i] == '>') {
op.emplace_back(i - 2, 5);
lst = i - 1;
break;
} else {
lst = i;
break;
}
}
for(int i = 0; i <= lst; i ++){
if(s[i] == '>') {
if(s[i + 1] == '-'){
int len = 4, j = i;
while(s[i + 1] == '-')
i ++, len ++;
op.emplace_back(j, len);
} else {
op.emplace_back(i, 5);
}
} else {
assert(false);
}
}
cout << "Yes " << op.size() << "\n";
for(auto [x, y]: op) cout << x + 1 << " " << y << "\n";
// check(n, op);
return;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
G. Expanding Array
這個題,我的做法就是直接暴搜,然後猛猛加最佳化就過了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = uint64_t;
using vi = vector<int>;
using pii = pair<int,int>;
const i64 P = 1e10;
unordered_set<i64> vis;
unordered_set<int> cnt;
void dfs(int l, int r) {
if(l > r) swap(l, r);
if(vis.insert((i64)l * P + r).second == false) return;
int mid = (l & r);
cnt.insert(mid);
if(l != mid and mid != r and mid != 0) dfs(l, mid), dfs(mid, r);
mid = (l | r);
cnt.insert(mid);
if(l != mid and mid != r and mid != 0) dfs(l, mid), dfs(mid, r);
mid = (l ^ r);
cnt.insert(mid);
if(l != mid and mid != r and mid != 0) dfs(l, mid), dfs(mid, r);
return ;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi a(n);
for(int i = 0; i < n; i ++)
cin >> a[i], cnt.insert(a[i]);
cnt.insert(0);
for(int i = 1; i < n; i ++)
if(a[i - 1] != a[i]) dfs(a[i - 1], a[i]);
cout << cnt.size();
return 0;
}
I. Good Partitions
首先我們求出序列中每一段連續不下降子串的長度,長度的 gcd 一定是可以的,並且 gcd 的因數也是可以的。除此之外,還有一種情況是捨去最後一段的 gcd 及其長度也是可行。
如果說我們可以求出 gcd,我們就可以\(O(\sqrt N\))的求出所有的因子。
現在我們考慮如何快速的實現修改和查詢 gcd,如果\(a[i] > a[i+1]\),則說明\(i\) 是一個不下降子串的結尾。我們可以新開一個陣列\(b[i]\),如果$a[i] > a[i + 1] $ 則\(b[i] = i\),否則\(b[i] = -1\)。此時我們找到每一個不是\(-1\)的數字,以及他前面第一個不是\(-1\) 的數字,我們就可以快速的求出不下降子串的長度。
這樣的話,我們需要就是單點修改和區間查詢,我們可以用線段實現這個操作。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = std::vector<int>;
struct Info {
int d, li, ri;
Info() {
d = 0;
li = ri = -1;
}
Info(int d, int li, int ri) : d(d), li(li), ri(ri) {}
Info operator+(const Info &b) {
Info res = *this;
if (res.li == -1) res.li = b.li;
if (b.ri != -1) res.ri = b.ri;
res.d = gcd(res.d, b.d);
if (ri != -1 and b.li != -1)
res.d = gcd(res.d, b.li - ri);
return res;
}
};
struct Node {
i32 l, r;
Info info;
Node *left, *right;
Node() {};
Node(int p, int x) {
l = p, r = p;
info = Info(0, x, x);
left = right = nullptr;
}
Node(int l, int r, Node *left, Node *right) : l(l), r(r), left(left), right(right) {
info = left->info + right->info;
}
};
Node *build(int l, int r, const vi &b) {
if (l == r) return new Node(l, b[l]);
i32 mid = (l + r) / 2;
auto left = build(l, mid, b);
auto right = build(mid + 1, r, b);
return new Node(l, r, left, right);
}
void modify(int p, int x, Node *cur) {
if (cur->l == p and p == cur->r) {
cur->info.li = cur->info.ri = x;
return;
}
int mid = (cur->l + cur->r) / 2;
if (p <= mid) modify(p, x, cur->left);
else modify(p, x, cur->right);
cur->info = cur->left->info + cur->right->info;
}
Info query(int n, Node *cur) {
if (cur->info.ri != n) return cur->info;
if (cur->l == cur->r) return Info();
Info res;
if (cur->left->info.ri != n)
res = res + cur->left->info;
else
res = res + query(n, cur->left);
if (cur->right->info.ri != n)
res = res + cur->right->info;
else
res = res + query(n, cur->right);
return res;
}
void solve() {
int n, q;
cin >> n >> q;
vi a(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
vi b(n + 1, -1);
for (int i = 1; i < n; i++) {
if (a[i] > a[i + 1]) {
b[i] = i;
}
}
b[0] = 0, b[n] = n;
auto root = build(0, n, b);
int d1 = root->info.d;
int d2 = query(n, root).d;
unordered_set<int> cnt;
if (d2 == 0) {
cout << n << "\n";
} else {
for (int i = 1; i * i <= d1; i++) {
if (d1 % i != 0) continue;
cnt.insert(i);
if (d1 / i != i) cnt.insert(d1 / i);
}
for (int i = 1; i * i <= d2 and d1 != d2; i++) {
if (d2 % i != 0) continue;
cnt.insert(i);
if (d2 / i != i) cnt.insert(d2 / i);
}
cout << cnt.size() << "\n";
}
for (int idx, val, ok; q; q--) {
cin >> idx >> val;
a[idx] = val, ok = 1;
if (idx - 1 >= 1 and a[idx - 1] > a[idx]) {
if (b[idx - 1] != idx - 1) {
b[idx - 1] = idx - 1;
modify(idx - 1, idx - 1, root);
ok = 0;
}
} else if (idx - 1 >= 1) {
if (b[idx - 1] != -1) {
b[idx - 1] = -1;
modify(idx - 1, -1, root);
ok = 0;
}
}
if (idx + 1 <= n and a[idx] > a[idx + 1]) {
if (b[idx] != idx) {
b[idx] = idx;
modify(idx, idx, root);
ok = 0;
}
} else if (idx + 1 <= n) {
if (b[idx] != -1) {
b[idx] = -1;
modify(idx, -1, root);
ok = 0;
}
}
if (ok) {
if (d2 == 0) cout << n << "\n";
else cout << cnt.size() << "\n";
continue;
}
d1 = root->info.d;
d2 = query(n, root).d;
cnt.clear();
if (d2 == 0) {
cout << n << "\n";
} else {
for (int i = 1; i * i <= d1; i++) {
if (d1 % i != 0) continue;
cnt.insert(i);
if (d1 / i != i) cnt.insert(d1 / i);
}
for (int i = 1; i * i <= d2 and d1 != d2; i++) {
if (d2 % i != 0) continue;
cnt.insert(i);
if (d2 / i != i) cnt.insert(d2 / i);
}
cout << cnt.size() << "\n";
}
}
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
J. Grand Prix of Ballance
讀題加模擬就做完了
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
void solve() {
int n, m, q;
cin >> n >> m >> q;
vector<vi> finsh(n + 1);
vector<set<int>> vist(n + 1);
int now_Level = -1;
for(int op, id, x; q; q --) {
cin >> op;
if(op == 1) {
cin >> x;
now_Level = x;
} else if(op == 2) {
cin >> id >> x;
if(x != now_Level) continue;
if(vist[x].insert(id).second == false) continue;
if(x == now_Level)
finsh[x].push_back(id);
} else {
cin >> id >> x;
if(x != now_Level) continue;
vist[x].insert(id);
}
}
vi points(m + 1);
for(int i = 1; i <= n; i ++) {
for(int v = m; auto j : finsh[i])
points[j] += v, v --;
}
vi rank(m);
iota(rank.begin(), rank.end(), 1);
ranges::sort(rank, [&](int x, int y) -> bool {
if(points[x] != points[y]) return points[x] > points[y];
return x < y;
});
for(auto i : rank)
cout << i << " " << points[i] << "\n";
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}
L. Recover Statistics
簽到題
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = std::vector<int>;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
i64 P50, P95, P99;
cin >> P50 >> P95 >> P99;
cout << 100 << "\n";
for(int i = 1; i <= 50; i ++)
cout << P50 << " ";
for(int i = 1; i <= 45; i ++)
cout << P95 << " ";
for(int i = 1; i <= 4; i ++)
cout << P99 << " ";
cout << P99 + 1 << "\n";
return 0;
}