Thank you for participating! We hope you enjoyed the problems.
Tutorial
Tutorial is loading...
Solution
t = int(input())
for tt in range(t):
n = int(input())
ans = 0
def dig_sum(n):
s = str(n)
sum = 0
for j in s:
sum += ord(j) - ord('0')
return sum
for i in range(n, n + 200):
if i - dig_sum(i) == n:
ans += 1
print(ans)
Tutorial
Tutorial is loading...
Solution
#include <bits/stdc++.h>
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define len(a) int(a.size())
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using namespace std;
const int mod = 998244353;
const int N = 1e6 + 228;
pair<int, int> zero = {-1, N};
void solve() {
int n;
cin >> n;
map<int, int> pos;
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
pos[a] = i;
}
int lst = -1;
vector<int> b(n);
for (int i = 0; i < n; ++i) cin >> b[i];
for (int i = 0; i < n; ++i) {
if (lst > pos[b[i]]) {
cout << "NO\n";
return;
}
lst = pos[b[i]];
}
cout << "YES\n";
}
int main(int argc, char* argv[]) {
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
}
Tutorial
Tutorial is loading...
Solution
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int p, q;
cin >> p >> q;
if (p < q && min(p / 2, q / 3) >= q - p){
cout << "Bob\n";
}
else{
cout << "Alice\n";
}
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2196B - Another Problem about Beautiful Pairs
Tutorial
Tutorial is loading...
Solution
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int SQ = 500;
void solve(){
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++){
cin >> a[i];
}
int ans = 0;
for (int i = 0; i < n; i++){
if (a[i] >= SQ){
for (int j = 1; i + a[i] * j < n; j++){
if (a[i + a[i] * j] == j){
ans++;
}
}
for (int j = 1; i - a[i] * j >= 0; j++){
if (a[i - a[i] * j] == j){
ans++;
}
}
}
else{
for (int j = 1; i + a[i] * j < n && j < SQ; j++){
if (a[i + a[i] * j] == j){
ans++;
}
}
}
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2196C1 - Interactive Graph (Simple Version)
Tutorial
Tutorial is loading...
Solution
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1'000'000'007;
vector<int> ask(int k){
cout << "? " << k << endl;
int l;
cin >> l;
if (l == -1){
exit(0);
}
vector<int> res(l);
for (int i = 0; i < l; i++){
cin >> res[i];
}
return res;
}
void solve(){
int n;
cin >> n;
vector<pair<int, int>> edges;
for (int i = 0; i < n; i++){
int prev = -1;
while(1){
int l = 1, r = (1 << 30);
while(l <= r){
int m = l + (r - l) / 2;
auto path = ask(m);
if (!path.empty() && path[0] < i + 1){
l = m + 1;
continue;
}
if (path.empty() || path[0] > i + 1 || (path.size() > 1 && path[1] > prev)){
r = m - 1;
}
else{
l = m + 1;
}
}
auto path = ask(l);
if (path.size() > 1){
edges.emplace_back(path[0], path[1]);
prev = path[1];
}
else{
break;
}
}
}
cout << "! " << edges.size() << endl;
for (auto [u, v] : edges){
cout << u << ' ' << v << endl;
}
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2196C2 - Interactive Graph (Hard Version)
Tutorial
Tutorial is loading...
Solution
#include<bits/stdc++.h>
using namespace std;
vector<int> ask(int k){
cout << "? " << k << endl;
int cnt;
cin >> cnt;
vector<int> res(cnt);
for (int i = 0; i < cnt; i++){
cin >> res[i];
res[i]--;
}
return res;
}
void solve(){
int n;
cin >> n;
int m = 0;
vector<vector<int>> g(n);
vector<int> cnt(n, -1);
function<void(int)> calc = [&](int v){
if (cnt[v] != -1){
return;
}
cnt[v] = 1;
for (int to : g[v]){
calc(to);
cnt[v] += cnt[to];
}
};
vector<int> prev = {0};
int k = 2;
while(1){
auto cur = ask(k);
if (cur.size() == 0){
break;
}
int com_pref = 0;
for (int i = 0; i < min(prev.size(), cur.size()); i++){
if (prev[i] != cur[i]){
break;
}
com_pref++;
}
if (prev.size() > com_pref){
calc(prev[com_pref]);
}
if (com_pref > 0){
g[cur[com_pref - 1]].push_back(cur[com_pref]);
m++;
}
if (cnt[cur[com_pref]] == -1){
k++;
}
else{
k += cnt[cur[com_pref]];
}
prev = cur;
}
cout << "! " << m << endl;
for (int i = 0; i < n; i++){
for (int to : g[i]){
cout << i + 1 << ' ' << to + 1 << endl;
}
}
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tests = 1;
cin >> tests;
for (int test = 0; test < tests; test++){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2196D - Double Bracket Sequence
Tutorial
Tutorial is loading...
Solution
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1'000'000'007;
void solve(){
int n;
cin >> n;
string s;
cin >> s;
vector<int> stay(n);
auto delete_cbs = [&](char open, char close){
vector<int> st;
for (int i = 0; i < n; i++){
if (s[i] == close){
if (!st.empty() && s[st.back()] == open){
st.pop_back();
}
else{
st.push_back(i);
}
}
else if (s[i] == open){
st.push_back(i);
}
}
for (int x : st){
stay[x] = 1;
}
};
delete_cbs('(', ')');
delete_cbs('[', ']');
int last_open = 0;
int cnt_open = 0, cnt_close = 0;
int ans = 1;
for (int i = 0; i < n; i++){
if (!stay[i]){
continue;
}
if (s[i] == '(' || s[i] == '['){
cnt_open++;
last_open = 1;
}
else{
cnt_close++;
if (last_open){
ans = 0;
}
last_open = 0;
}
}
if (cnt_open % 2 == 0 || cnt_close % 2 == 0){
ans = 0;
}
ans += (cnt_open + cnt_close) / 2;
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
2196E1 - Fuzzy Concatenation (Easy Version)
Tutorial
Tutorial is loading...
2196E2 - Fuzzy Concatenation (Hard version)
Tutorial
Tutorial is loading...
Solution
#include <bits/stdc++.h>
using namespace std;
template <typename T>
struct SparseTable{
int n, r;
vector<vector<T>> t;
void build(vector<T> &a) {
n = a.size();
r = 32 - __builtin_clz(n);
t.resize(r, vector<T>(n + 1));
for(int i = 1; i <= n; ++i) t[0][i] = a[i - 1];
for(int k = 1; k < r; ++k) {
for(int i = 1; i + (1 << k) - 1 <= n; ++i) {
t[k][i] = f(t[k - 1][i], t[k - 1][i + (1 << (k - 1))]);
}
}
}
T query(int l, int r) {
int k = 31 - __builtin_clz(r - l + 1);
return f(t[k][l], t[k][r - (1 << k) + 1]);
}
inline T f(T x, T y){
return min(x, y);
}
};
struct SuffixArray{
int n;
vector<int> sa;
vector<int> lcp;
vector<int> _s;
vector<int> _inv_sa;
SparseTable<int> _st_lcp;
SuffixArray(){}
void build(const string& s){
_s.assign(s.size(), 0);
for (int i = 0; i < s.size(); i++){
_s[i] = s[i];
}
_build(_s);
_build_lcp_array();
_st_lcp.build(lcp);
}
void build(const vector<int>& s){
_s.assign(s.size(), 0);
for (int i = 0; i < s.size(); i++){
_s[i] = s[i];
}
_build(_s);
_build_lcp_array();
_st_lcp.build(lcp);
}
void _build(const vector<int>& s){
map<int, int> mp;
for (int ch : s){
mp[ch] = 0;
}
int cc = 1;
for (auto& [key, val]: mp){
val = cc++;
}
n = s.size() + 1;
vector<int> c(n);
sa.assign(n, 0);
for (int i = 0; i < s.size(); i++){
c[i] = mp[s[i]];
sa[i] = i;
}
c[n - 1] = 0;
sa[n - 1] = n - 1;
for (int i = 1; (i >> 1) < n; i <<= 1){
if (i != 1){
for (int j = 0; j < n; j++){
sa[j] = (sa[j] - (i >> 1) + n) % n;
}
}
vector<int> cnt(n);
for (int j = 0; j < n; j++){
cnt[c[sa[j]]]++;
}
int su = 0;
for (int j = 0; j < n; j++){
su += cnt[j];
cnt[j] = su - cnt[j];
}
vector<int> new_sa(n);
for (int j = 0; j < n; j++){
new_sa[cnt[c[sa[j]]]++] = sa[j];
}
sa.swap(new_sa);
if (i != 1){
vector<int> new_c(n);
new_c[sa[0]] = 0;
for (int j = 1; j < n; j++){
if (c[sa[j]] > c[sa[j - 1]] || c[(sa[j] + (i >> 1)) % n] > c[(sa[j - 1] + (i >> 1)) % n]){
new_c[sa[j]] = new_c[sa[j - 1]] + 1;
}
else{
new_c[sa[j]] = new_c[sa[j - 1]];
}
}
c.swap(new_c);
}
}
}
void _build_lcp_array(){
lcp.assign(n - 1, 0);
_inv_sa.assign(n, 0);
for (int i = 0; i < n; i++){
_inv_sa[sa[i]] = i;
}
for (int i = 0; i < n; i++){
if (_inv_sa[i] == n - 1){
continue;
}
lcp[_inv_sa[i]] = 0;
if (i > 0 && _inv_sa[i - 1] != n - 1){
lcp[_inv_sa[i]] = max(0, lcp[_inv_sa[i - 1]] - 1);
}
int len = min(n - 1 - i, n - 1 - sa[_inv_sa[i] + 1]);
while (lcp[_inv_sa[i]] < len && _s[i + lcp[_inv_sa[i]]] == _s[sa[_inv_sa[i] + 1] + lcp[_inv_sa[i]]]){
lcp[_inv_sa[i]]++;
}
}
}
int get_lcp(int i, int j){
assert(i != j);
i = _inv_sa[i];
j = _inv_sa[j];
if (i > j){
swap(i, j);
}
j--;
return _st_lcp.query(i + 1, j + 1);
}
};
void solve(){
int n, m;
cin >> n >> m;
string s, t;
cin >> s >> t;
string all = s + "%" + t;
SuffixArray suff_array;
suff_array.build(all);
all += '#';
vector<int> from_s;
for (int i = 0; i < n + m + 2; i++){
if (suff_array.sa[i] < n){
from_s.push_back(i);
}
}
function<pair<int, int>(int, int, char, int)> compare_suff = [&](int start, int pos, char ch, int suff_num){
if (suff_num == 0 || suff_num > n){
return pair<int, int>{1, 0};
}
pos -= start;
suff_num--;
suff_num = suff_array.sa[from_s[suff_num]];
int lcp1 = suff_array.get_lcp(suff_num, n + 1 + start);
if (lcp1 < pos){
char ch1 = all[suff_num + lcp1];
char ch2 = all[n + 1 + start + lcp1];
if (ch1 < ch2){
return pair<int, int>{1, lcp1};
}
else{
return pair<int, int>{-1, lcp1};
}
}
else if (lcp1 > pos){
char ch1 = all[suff_num + pos];
char ch2;
int len = pos;
if (ch1 != ch){
ch2 = ch;
}
else{
len = lcp1;
ch1 = all[suff_num + lcp1];
ch2 = all[n + 1 + start + lcp1];
}
if (ch1 < ch2){
return pair<int, int>{1, len};
}
else{
return pair<int, int>{-1, len};
}
}
char ch1 = all[suff_num + lcp1];
char ch2 = ch;
if (ch1 < ch2){
return pair<int, int>{1, pos};
}
else if (ch1 > ch2){
return pair<int, int>{-1, pos};
}
int lcp2 = suff_array.get_lcp(suff_num + lcp1 + 1, n + 1 + start + lcp1 + 1);
ch1 = all[suff_num + lcp1 + 1 + lcp2];
ch2 = all[n + 1 + start + lcp1 + 1 + lcp2];
if (ch1 < ch2){
return pair<int, int>{1, pos + 1 + lcp2};
}
else{
return pair<int, int>{-1, pos + 1 + lcp2};
}
};
function<int(int, int, char)> get_max_len = [&](int start, int pos, char ch){
int suff_len = n + 1 + start;
int l = 0, r = from_s.size();
while(l <= r){
int m = l + (r - l) / 2;
if (compare_suff(start, pos, ch, m).first == -1){
r = m - 1;
}
else{
l = m + 1;
}
}
int res = 0;
res = max(res, compare_suff(start, pos, ch, l - 1).second);
res = max(res, compare_suff(start, pos, ch, l).second);
return res;
};
int ans = 0;
int start = 0;
int pred = -1;
for (int i = 0; i < m; i++){
int mx_len = 0;
for (char ch = 'a'; ch <= 'z'; ch++){
mx_len = max(mx_len, get_max_len(start, i, ch));
}
pred = max(pred, mx_len);
if (mx_len < i - start + 1){
ans++;
start += pred;
pred = -1;
i = start - 1;
continue;
}
}
if (start != m){
ans++;
}
cout << ans << '\n';
}
signed main()
{
#ifdef FELIX
auto _clock_start = chrono::high_resolution_clock::now();
#endif
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
#ifdef FELIX
cerr << "Executed in " << chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now()
- _clock_start).count() << "ms." << endl;
#endif
return 0;
}
Tutorial
Tutorial is loading...
Solution
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define all(x) x.begin(), (x).end()
#define rall(x) x.rbegin(), (x).rend()
using namespace std;
vector<pair<int, int>> theSolve(int n, int m) {
if (m == 1 || m == 2 || m == 4 || m == 6) {
return {};
}
if (m == 12) {
vector<pair<int, int>> e;
for (int x = 1; x <= 6; x++) {
for (int y = x + 1; y <= 6; y++) {
if (max(x, y) >= 4) {
e.pb({x, y});
}
}
}
return e;
}
if (n == 6 && m == 11) {
return {{1, 2},
{1, 3},
{2, 4},
{2, 5},
{2, 6},
{3, 4},
{3, 5},
{3, 6},
{4, 5},
{4, 6},
{5, 6}};
}
if (n == 8 && m == 22) {
vector<pair<int, int>> e;
for (int v = 1; v <= 7; v++) {
for (int u = v + 1; u <= 7; u++) {
e.pb({v, u});
}
}
e.pb({7, 8});
return e;
}
if (n == 10 && m == 39) {
vector<pair<int, int>> e;
for (int x = 1; x <= n - 1; x++) {
for (int y = x + 1; y <= n - 1; y++) {
e.pb({x, y});
}
}
for (int x = 1; x <= 3; x++) {
e.pb({n, x});
}
return e;
}
vector<pair<int, int>> edges;
if (n % 2 == 1) {
while (m <= (n - 2) * (n - 3) / 2) {
n -= 2;
}
int q = (2 * m) / n, r = (2 * m) % n;
if (q % 2 == 0) {
for (int v = 0; v < n; v++) {
for (int p = 0; p < q / 2; p++) {
int u = (v + 1 + p) % n;
edges.pb({v + 1, u + 1});
}
}
for (int v = 0; v < r / 2; v++) {
edges.pb({v + 1, (v + n / 2) % n + 1});
}
} else {
int d = (n - r) / 2;
for (int v = 0; v < n; v++) {
for (int p = 0; p < (q + 1) / 2; p++) {
if (v % 2 == 0 && p == 0 && d) {
d--;
continue;
}
int u = (v + 1 + p) % n;
edges.pb({v + 1, u + 1});
}
}
}
return edges;
}
int rest = n * (n - 1) / 2 - m;
if (rest == 0 || rest == 1 || rest == 2 || rest == 4 || rest == 6) {
return {};
}
if (m <= (n - 1) * (n - 2) / 2) {
return theSolve(n - 1, m);
}
vector<pair<int, int>> inv_e = theSolve(n - 1, n * (n - 1) / 2 - m);
for (auto &p : inv_e) {
if (p.first > p.second) {
swap(p.first, p.second);
}
}
sort(all(inv_e));
int i = 0;
vector<pair<int, int>> e;
for (int v = 1; v <= n; v++) {
for (int u = v + 1; u <= n; u++) {
if (i < (int) inv_e.size() && inv_e[i] == (pair<int, int>) {v, u}) {
i++;
continue;
}
e.pb({v, u});
}
}
return e;
}
void solve() {
int n, m;
cin >> n >> m;
vector<pair<int, int>> e = theSolve(n, m);
if (e.empty()) {
cout << "No\n";
} else {
cout << "Yes\n";
for (auto &[a, b] : e) {
cout << a << ' ' << b << '\n';
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
}
For those who come after.








Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).
Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).
Auto comment: topic has been updated by FelixArg (previous revision, new revision, compare).
Another solution for div1 D is to just simulate the brackets until you fail. At that moment change this bracket to something else (because you don't know what to change it to, keep all (at most 3) possibilities. At the end the one closest to (0, 0) will give you the minimum changes required.
362523300
Truth be told, I did not manage to prove that this is correct. It is mostly intuition from the simplified problem of only one type of paranthesis (only change when prefix is negative and resolve the end). Would be great if someone could prove/disprove/hack this solution
can you explain more to this what exactly do you mean by closest to 0,0
Assume you have $$$x$$$ open round paranthesis and $$$y$$$ open square paranthesis. Then the minimum number of operations to get a good string is $$$\frac{x+y}{2}$$$. Take the minimum of these values.
Am not a gm like you lmao to understand that little info if you ever get free please describe that method comprehensively I loved that solution with mindist
Consider how to determine if a sequence is valid. Maintain two sums $$$x, y$$$. For
(, $$$x \leftarrow x+1$$$; for), $$$y \leftarrow y+1$$$, and square brackets do the similar operation on $$$y$$$. A sequence is valid if and only if $$$x, y \ge 0$$$ at any moment, and finally $$$x = y = 0$$$.For the single bracket type problem, the optimal strategy is to change
)to(when $$$sum \lt 0$$$. For two types of brackets, an invalid)might be changed to one of(,[, or]. Maintain these three results, and in the subsequent process, avoid extra operations as much as possible unless none of these states remain valid.This looks essentially the same as the official solution. They may lead to the same construction.
We can do Div1E in $$$O((n+m)\log (n+m))$$$ time (with no factors of $$$k$$$).
We want to find the maximum $$$d$$$ where:
Consider all the positions $$$q$$$ of substrings of $$$s$$$ such that $$$s_{q-\ell}\dots s_{q-2}s_{q-1} = t_{p_t}t_{p_t+1}\dots t_{p_t+\ell-1}$$$ . These positions form a segment in the suffix array of the reversed $$$s$$$ . Associate the suffix of the reversed $$$s$$$ ($$$s_{q-1}s_{q-2}\dots$$$) with a suffix of $$$s$$$ ($$$s_{q+1}s_{q+2}\dots$$$). Now we just need to find the maximum LCP between the following characters in $$$t$$$ and $$$s_{q+1}s_{q+2}\dots$$$ , but the value $$$q$$$ must be taken from the corresponding segment of the suffix array of the reversed $$$s$$$ .
Eventually, the task is reduced to a typical query: find the minimum element in a subarray $$$(a_l, a_{l+1}, \dots , a_r)$$$ but no less than $$$x$$$ (and also the maximum but no greater than $$$x$$$). This can be solved using a wavelet matrix.
362520685
FelixArg Please fixed the given code for div2A. I think it was written for div2B.
Thanks, fixed now
brute force has passed div2 D: https://mirror.codeforces.com/contest/2197/submission/362486786
And they disable hacks for A-D. and they themselves don't cover all the test cases.
Anyways, problem set was very good. But they shouldn't disable hacks if they can't cover all edge cases.
2196C2 is a wonderful problem!
really a bad contest for me can't debug the div 2 B . can anyone one help me to find the test case where this code not working 362482618. my idea is that all the same elements should be consecutive in array a,and there should not be any diagonal intersection ie- p=1,2 a=2,1 and after storing the index of all the same elements. I will check if the p[i]->index of i in the permutation is in the range of min(i)-1 and max(i)+1,where min(i) is the minimum index of i in the array a and max(i) is the maximum element in the array a. because we can copy one forward and one backward . if i is not present in the array leave it.
Failing test case:
Your code returns NO, while the answer is YES
thanks bro
I found a binary search solution for div2A. The idea is that suppose an infinite sequence of integers where $$$i$$$th element of the sequence is $$$i - d(i)$$$ where $$$d(i)$$$ equals to the sum of the digits of $$$i$$$. Then this sequence will be non-decreasing. So we can binary search for $$$x$$$ in this sequence taking the lower bound and upper bound in a way such that any $$$x$$$ in the given range $$$1≤x≤$$$$$$10$$$$$$9$$$ can be found if present. If $$$x$$$ is present, then the answer is $$$10$$$, otherwise $$$0$$$. You can see my submission 362438894 for implementation. In this code, I have also utilized the fact that $$$x$$$ must be divisible by $$$9$$$ to be in the sequence, which i guess was not necessary to check.
My idea for div2 D was to speedup the bruteforce method and avoid recalculation. When iterating over k for $$$j = i + k \cdot a_i$$$, for a given $$$i$$$, we will do the calculations considering the pair $$$(a_i, i \ mod \ a_i)$$$. This means that for any index $$$j$$$ that we encounter in further iterations in which $$$(a_j, j \ mod \ a_j) = (a_i, i \ mod \ a_i)$$$ we can skip it, as we have previously calculated its pairings. The idea behind that is that for all indices with this pairing, they would go through the same $$$j$$$'s and have the same value for contributing to the equation.
When finding such a pair which has not been calculated previously, we can maintain a set with all indices $$$j$$$ where $$$a_j=a_i$$$ and incrementing the answear if $$$j-a_i \cdot a_j$$$ is in the set.
My code: 362526064
The complexity is roughly $$$O(n \sqrt{n} log(n))$$$, i feared receiving a tle but then i noticed that it would be fast enough with 5 minutes for the contest ending and got AC.
You can use an
unordered_setinstead of anset, which has an amorized time complexity of O(1) per insertion and query. The only moment when you want to use a normalsetis when you want to remove/query the largest/smallest element, or you care about the elements being sorted, neither of which you do in this case.After i made this comment i had actually tried submiting with a
unordered_setto see if it would gain some performance, but it actually performed worse. I had this experience a lot when switching betweensetandunordered_setbecause normally the test cases are made in such a way that all the element may go to the same bucket or it happens that you get really unlucky and some buckets start getting a little too dense, so i normally usesetby standard.I also noticed that i didn't really needed a set, and could just use an auxiliary vector that said if an element was already considered in some other iteration, thus making the algorithm work in $$$O(n\sqrt{n})$$$. Here are the subimissions:
on-contest with
set(734ms): 362526064using
unordered_set(1171ms): 362541967optimized with no set (359ms): 362705070
You're right — when accessed many times, but not with many distinct elements
unordered_setoffen does end up slower thansset, but over 90% of the time you can just use abitsetwhich is always faster (you just have to remember thatbitset<200'000> bis linear and so is setting it to0). If you change your vector to bitset, you go down to 328ms (366405742). The difference here is small, but visible and in some cases can be much larger, so it's usually better to use a bitset or a vector<char> when you need to dynamically change the sizeI believe the memory limit of E2(div1) is too small. You will immediately get MLE if you build two SAMs.
There's a $$$O(m\sqrt{n\Sigma})$$$ for div1E, where $$$\Sigma = 26$$$ is the size of alphabet. For a string with length $$$L$$$, there's at most $$$L\Sigma$$$ different possible strings, and we maintain all of their positions in SAM. When the length $$$L$$$ exceed a threshold $$$B$$$, do the bruteforce in $$$O(n)$$$ mention in the solution for E1.
Here the time complexity is $$$\frac{m}{B}\cdot \Sigma \cdot B^{2} + \frac{m}{B} \cdot n$$$, which is $$$O(m\sqrt{n\Sigma})$$$ when $$$B = \sqrt{\frac{n}{\Sigma}}$$$. The first part of the solution is not full and the solution is easy to squeeze.
I wrote a brute-force for div1 E1. The time complexity is O(n*m) and I passed by making constant number small.
362519663
Can this be hacked?
Is string slower than character array in C++?
creating variable names with chinese characters actually works?
Yeah. Now many compilers have supported UTF-8 characters
In the Div2A editorial, why do we need to check the range from x to x + 83? The problem states that x is between 1 and 10^9, so shouldn’t we only need to check i in the range from x to x + 81?
That is something you will notice in various solution. It is just a safe redundancy to make sure there is no runtime or logical error. The most used example that I have seen is when the author creates an array a[N], where N would be 2e5 + 10. Although, the size may never exceed 200,000. It is just there to make sure that any unexpected error does not appear.
In this case, it does not matter that we check for 82 and 83. It is just there. If you observe other submission for same problem, you may find many using x to x + 100.
Got that. Thanks for clarification :). Yes I have seen solution of red coders they used till x+100.
ConstraintForces
Tried hell a lot to debug div2B, pls help
my approach: in a map i store, the indices where each element appeared in the permutation array. an integer pivotIndex, indicates, till now, which was the last element from which we copied values. [to be precise, if I am at some index i, then pivotIndex represents the index of the element used to correct the p[i].] i iterate through the permutaion array, there will be three possibilities
b. mp[a[i]] > i, then check if till required index, all elements are a[i] only, if yes, very nice new pivotIndex = mp[a[i]];
else not possible
I tried C) fraction by say let say we start with 10,14 now its not 2/3 so we find next 2/3 ratio which is 8 and 12, now alice wants to make it 7 ( 8-1) as soon as possible, while Bob only has to made 14 to 12, so Bob needs 2 Alice needs 3, thats not possible even if Alice plays first, so Bob wins, this approach was not working for this big sample test case, 7000000000000000 10487275715782582, as I was not able to find which is the next closest p/q=2/3 ratio values of p and q are, so I used a loop for it but that loop is not stopping so I took some help from claude but still its not working this is my https://mirror.codeforces.com/contest/2197/submission/362586660
hey here is how i thought about the problem
bob will in if any value k is such that by p-k/q-k = 2/3 meaning we took 2/3 this ratio then multiplied both up and down with some value 'm' then added k to both . so by substracting k now from p,q they both reaches the desired value where p/q=2/3
now lets say p=2m+k and q=3m+k so q-p=3m+k-2m-k=m there fore we now need to check if p and q gives exactly same reminder with m or not( k) if so then we are happy and then we check when p and q divided with m does we really get 2 and 3 ....and we are done this was my approach but it didnt worked too sad
https://mirror.codeforces.com/contest/2197/submission/367139516
Loved the contest but its sad that Div2D, people got their n^2 sol passed.
This is my thought process when writing Div1 D:
We can obviously think of a wrong simple greedy approach: remove all legal bracket matches, and it is easy to find that the remaining ones need to be paired up, so we can directly divide the number of remaining ones by 2
We can find an obvious counterexample to prove the approach is incorrect: when the sequence of parentheses we remove is
)(, no matter what, we need to perform two operations to make it valid.However, we found that this situation is very rare, and the approach only goes wrong when the parenthesis sequence grows into a pattern like
)))(((. Therefore, after special handling, this problem can be solvedI did something somewhat similar, but more convoluted. In the first traversal, pair up and "remove" those elements — 0 cost. Then, no pair remains and we need at least 1 operation to make each pair. Hence, the answer is at least half of the amount of remaining chars. It turns out this lower bound can almost always be achieved. And if it can't, there is only one more case: the lower bound + 1 (because a single pair requires 2 operations).
Call the chars '[' and '(' as S (start). Call the charss ')' and ']' as E (end). It is possible to prove that the extra cost occurs iff the amount of Es is odd and the rightmost E occurs before the leftmost S.
Hence, the problem is reduced to making the optimal pair ups in the first step: let's try to let the leftmost remaining '(' or '[' (i.e S) as to the left as possible. The opposite for ')', ']' (i.e E). A simple greedy works: traverse from right to left in terms of the starting chars. For the ending chars, mantain a stack.
Essentially, they are the same.
The essence of my approach is to pair brackets in the same direction, while yours essentially involves pairing those in different directions.
It is easy to prove that the ultimate cost of these two approaches is the same. However, my approach does not require actual pairing and can directly compute the answer in $$$O(1)$$$ (of course, during the competition, I was too lazy to write two pointers to determine positions, so I directly sorted and took the index position. Therefore, my code runs in $$$O(n\log n)$$$, but it could easily run in $$$O(n)$$$)
My Div2 A solution:
Let's think about denoting $$$y$$$ in the decimal notation. If $$$y = 100 a_2 + 10 a_1 + a_0 \; (0 \le a_i \le 9)$$$, then $$$d(y) = a_2 + a_1 + a_0$$$, so $$$x = y - d(y) = 99 a_2 + 9 a_1$$$.
More generally, if $$$y$$$ is denoted as: $$$\displaystyle y = \sum_{i=0}^n 10^i a_i \; (0 \le a_i \le 9)$$$, then $$$\displaystyle x = \sum_{i=1}^n (10^i - 1) a_i$$$. Note that $$$a_0$$$ does not appear in $$$x$$$, because $$$(10 ^ 0 - 1)a_0 = 0$$$. Since $$$x \le 10^9$$$, having $$$n = 9$$$ is sufficient.
Therefore, for every $$$a = [a_1, a_2, \ldots, a_9]$$$ such that $$$\displaystyle x = \sum_{i=1}^9 (10^i - 1) a_i$$$, you have $$$10$$$ different numbers of $$$y$$$ that satisfies $$$y - d(y) = x$$$ (you have $$$10$$$ here because you can choose $$$a_0$$$ freely).
It turns out the representation of $$$a$$$ is unique for $$$x$$$ that can be denoted in the above way.
Proof. The maximum value that can be represented in $$$m$$$ digits is:
The minimum unit of the $$$(m+1)$$$-th digit is $$$\displaystyle 10^{m+1} - 1$$$, which is larger than $$$M$$$. This means that you can greedily determine the values of $$$a_i$$$ from the higher digits $$$(a_9, a_8, \ldots, a_1)$$$ without negative consequences. So, you can consider this $$$a$$$ as some form of positional notation system, where only some set of numbers can be represented.
So, the final answer is $$$10$$$ if you can find a suitable $$$a$$$ with the above greedy method. Otherwise the answer is $$$0$$$.
B is a great problem
I am so consufed about Div1E1. With the limitations as they are a light-weight $$$O(nm)$$$ solution passes with flying colors: 362473782.
A simple $$$ O(\frac{nm} {w} ) $$$ solution passes E2 aswell. 362643254
Can someone help me with div2.E? I just can't find the mistake. WA on test 7.
For the div2D, why is it enough to check upto k < sqrt for a[i] < sqrt? Isn't it possible that there are some answer where k >= sqrt?
For the case where a[i]=sqrt, let's say that k is some a[j] where j then the pair (j,i) will be counted once while iterating for a[j] (as if a[j]>=sqrt we iterate in both directions).
Similarly if j>i it will be counted.
Can anyone help me find where i am going wrong and a counter example would be really appreciated where my code takes more than (n+m) queries. My logic may be entirely or partially incorrect. Thanks!
Loved the problem Div2/E2 :3
Can someone tell me why my same solution for Div2D is giving tle when using map 362858481 but passes when using set 362858833 ?
Edit: I found the problem.
In div2D, isn't it a typo?
"If $$$a_i \geq B$$$ and $$$a_j \lt B$$$, then the pair will be counted when we iterate through candidates for j;" — shouldn't it be "candidates for i"?
I assume i < j and for $$$a_j \lt B$$$, when j is fixed, only indices i>j would be considered (according to strategy "iterate through candidates only forward"). If i would be fixed instead, we're guaranteed there won't be more than $$$\lceil\sqrt{n}\rceil$$$ checks (total for both sides, forward and backward) for j ("it is $$$\frac{n}{B}$$$") and that mentioned pair would be covered.
can someone please explain div2 D in simpler terms
we want a[i] * a[j] = j — i
let's make an assumption, a[i] & a[j] are both larger than sqrt(j — i), then, a[i] * a[j] would be larger than j — i. Hence our assumption is wrong, and the opposite of our claim is true, i.e. either a[i] <= sqrt(j — i) or a[j] <= sqrt(j — i). (If you know DeMorgan's law it'll be clear how we inverted the statement).
by the previous statement, we can pair an element <= sqrt(n) with an element <= sqrt(n). And, we can also pair an element <= sqrt(n) with an element >= sqrt(n). These two scenarios are allowed, but we can't pair two elements >= sqrt(n).
iterate through the elements and call the current element x.
if x >= sqrt(n): we need an element y with a distance d from the current element such that x * y = d. From the equation we see that d is a multiple of x. Hence, x <= d = x * y <= n — 1 (the farthest pair possible)
rewriting, x <= x * y <= (n — 1) / x --> 1 <= y <= (n — 1) / x, we said that x >= sqrt(n), that means the worst case for the value of y is sqrt(n) (plugging the smallest value of x = sqrt(n) to make (n — 1) / x as large as possible).
You can iterate through the possible values of y, setting d = x * y, and checking if the element behind the current element by d equals y, or the element in front of you by d equals y.
If x <= sqrt(n): we want to pair it with an element <= sqrt(n), and not with an element >= sqrt(n) since in the previous part we did that already.
since we want to pair it with an element <= sqrt(n), we can just brute force this value (call it y). 1 <= y <= sqrt(n). We want an element that equals y with a distance x * y from the current element, rather than checking the indices of y in the array, we can instead use the info that d = x * y and check the element behind me by d and in front of me by d and seeing if it equals y or not. (you need to handle the collisions btw)
I've commented an another solution below you maybe it'll make sense. Hope that helped :>
Another solution for B div1:
let d be the the distance j — i (d = j — i), x = a[i], y = a[i].
x * y = d.
let x = min(x, y), y = max(x, y).
we know that x <= sqrt(d) and y >= sqrt(d) ==> y ^ 2 >= d.
we also know that d % y = 0, i.e. d = c * y where c is some constant. Hence, y <= d.
since d is the difference of the indices, it's max value is n — 1, we can write it as d <= n for the sake of simplicity.
y <= d <= min(n, y ^ 2), but d = c * y
y <= c * y <= min(n, y ^ 2), dividing by y we get
1 <= c <= min(n / y, y), that worst case for min(n / y, y) is y = sqrt(n). Hence, 1 <= c <= sqrt(n).
we can iterate through the elements of the array supposing the current element is the max between the elements in the pair (i.e. y in the explanation), and brute forcing the value of c to get every possible value of d as d = c * y.
I'm afraid not even the problem writers know what is going on on C2 — Interactive Graph. Evidence of this is the fact that, on their solution, they compute the longest common prefix of the vectors $$$prev$$$ and $$$cur$$$, but that is not needed because the longest common prefix always has length $$$cur.size()-1$$$. Also, they talk about "connected components" on the editorial, which doesn't help much, because the exercise doesn't have connected components.
My take on their solution is the following:
The sequence of paths in lexicographical order simulates a lexicographical DFS traversal of the DAG. Indeed, when you do a query $$$k$$$, the interactor returns the call stack at the moment $$$k$$$.
With this, we sketch the general idea: we will do a DFS over the DAG, but we will try to avoid visiting a vertex twice (this way we get linear complexity).
Let's do queries from $$$k = 2$$$, then $$$k+1$$$, $$$k+2$$$, and so on, until we visit a vertex for the second time. During that process, let's also keep at what $$$k$$$ a vertex first appeared, and at what $$$k$$$ it left the stack. To do that, we only need the current DFS stack $$$p$$$ and the previous one $$$prev$$$. Notice that the longest common prefix of those stacks is always $$$p.size()-1$$$, because $$$p$$$ was made by removing elements from the back of $$$prev$$$ and then appending a new element.
Whenever we visit a vertex $$$u$$$ for the second time, we already know how many paths start from it: that amount is $$$timeOut[u] - timeIn[u]$$$. So, instead of querying at $$$k+1$$$ now (which will visit those paths), let's go to $$$k + timeOut[u] - timeIn[u]$$$ instead. This will skip exactly all the paths that start on $$$u$$$, and this will effectively make our DFS go to the vertex after $$$u$$$ in DFS order.
This algorithm does exactly the walk a DFS (without vertex repetition) would do, and therefore, the edges of the graph will be the ones made by the 2 last vertices of $$$p$$$ (check code for more details).
Submission
FOR THOSE WHO COME AFTER...
The editorial is not linked to the round
Can someone read my solution for Div2/E1 (Interactive Graph — Simple version) and please explain how the number of queries made by my solution never exceeds 32*(n+m)?
I am unable to mathematically prove my solution's optimality as it tends to get quite rigorous at least for me. I am not even sure if my solution is optimal and whether if it might get hacked by some test case even if it gets accepted for now.
Intuition for my solution: I begin with a linear iteration where I start with the first path (i = 1). You can make an observation that while doing so, if a particular vertex appear at the same position in a series of consecutive paths and then it changes its position or does not appear in the next path at all, that means the entire sub-tree from that vertex has already been encountered and we can store the edges involved in that sub-tree since we iterate through all the paths from that vertex for the first time. Then, we also store the number of paths that originate from that vertex in count array (in my solution) because if that vertex appears for another time, we can directly skip to the path i = i+count[vertex] since we have already encountered the entire sub-tree from that vertex so there is no new edge to be stored.
Please go through my solution to understand what I am talking about.
Submission: 364466471
Some additional notes on the editorial solution for 1D (below $$$k$$$-pair denotes a pair which costs $$$k$$$ to make correct):