Идея: AndreyPavlov
Подготовка: AndreyPavlov
Разбор: AndreyPavlov
Заметим, что существует два варианта какие числа брать, чтобы их сумма была нечётной: $$$3$$$ нечетных числа; $$$2$$$ четных и $$$1$$$ нечетное. Сохраним все индексы четных и нечетных чисел в два массива, и проверим оба случая.
def solve():
n = int(input())
a = list(map(int, input().split()))
odd, even = [], []
for i in range(n):
if a[i] % 2 == 0:
even.append(i + 1)
else:
odd.append(i + 1)
if len(odd) >= 1 and len(even) >= 2:
print("YES")
print(odd[0], even[0], even[1])
elif len(odd) >= 3:
print("YES")
print(odd[0], odd[1], odd[2])
else:
print("NO")
t = int(input())
for test in range(t):
solve()
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> odd, even;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (x % 2 == 0) {
even.push_back(i);
} else {
odd.push_back(i);
}
}
if (odd.size() >= 3) {
cout << "YES\n";
cout << odd[0] << " " << odd[1] << " " << odd[2] << '\n';
} else if (odd.size() >= 1 && even.size() >= 2) {
cout << "YES\n";
cout << odd[0] << " " << even[0] << " " << even[1] << '\n';
} else {
cout << "NO\n";
}
}
}
Идея: 74TrAkToR
Подготовка: qualdoom
Разбор: qualdoom
Давайте заметим, что нам не имеет смысла разбивать больше, чем на $$$k = 2$$$ подотрезков. Докажем это.
Пусть мы как — то разбили массив $$$a$$$ на $$$m > 2$$$ подотрезков : $$$b_1, b_2, \ldots, b_m$$$. Заметим, что $$$\gcd(b_1, b_2, \ldots, b_m) \le \gcd(b_1 + b_2, b_3, \ldots, b_m)$$$, так как если $$$b_1$$$ и $$$b_2$$$ были кратны $$$\gcd(b_1, b_2 , \ldots, b_m)$$$, значит и $$$b_1 + b_2$$$ тоже кратно $$$\gcd(b_1, b_2, \ldots, b_m)$$$. А значит, мы можем вместо $$$b_1$$$ и $$$b_2$$$ использовать $$$b_1 + b_2$$$, и ответ не ухудшится, таким образом, всегда выгодно использовать не более $$$k = 2$$$ подотрезков.
Как найти ответ? Пусть $$$s$$$ — сумма массива $$$a$$$. Давайте допустим $$$pref_i = {\sum_{j = 1}^{i} a_j}$$$, тогда ответ это $$$\max\limits_{1 \le i < n}(\gcd(pref_i, s - pref_i)$$$.
from math import gcd
t = int(input())
for test in range(t):
n = int(input())
a = list(map(int, input().split()))
s = 0
for i in range(n):
s += a[i]
ans = 0
pref = 0
for i in range(n - 1):
pref += a[i]
ans = max(ans, gcd(pref, s - pref))
print(ans)
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
long long s = accumulate(a.begin(), a.end(), 0ll), cur = 0;
long long ans = 1;
for (int i = 0; i < n - 1; i++) {
cur += a[i], s -= a[i];
ans = max(ans, __gcd(s, cur));
}
cout << ans << "\n";
}
}
Идея: AndreyPavlov
Подготовка: qualdoom, AndreyPavlov
Разбор: qualdoom, AndreyPavlov
У этой задачи есть два похожих решения, мы расскажем оба.
Вычтем $$$1$$$. Что теперь можно сказать о количестве единиц в начале двоичной записи числа? Их ровно $$$cnt - cnt_w + 1$$$, где $$$cnt$$$ — количество единичных битов после вычитания единички, а $$$cnt_w$$$ — до вычитания. Теперь вычтем их, для этого нужно вычесть число $$$2^{cnt - cnt_w - 1} + 1$$$ и продолжим алгоритм. Но такой алгоритм делает в худшем $$$60$$$ запросов. Чтобы сэкономить запросы заметим, что мы знаем количество единиц после того, как уберем единицы с начала, следовательно делать ещё один запрос для этого бесполезно. Тогда вместе с тем, как уберем единицы с начала, вычтем сразу и единичку. По итогу будет совершенно не более $$$cnt$$$ операций, где $$$cnt$$$ — изначальное количество единичных битов в записи числа $$$n$$$. Это число не превосходит $$$O(log_2 (n))$$$, в свою очередь $$$log_2 (n)$$$ не превосходит 30, что укладывается в ограничения.
Пусть $$$ans$$$ — искомое число $$$n$$$, а $$$was$$$ — изначальное количество битов в числе $$$n$$$. Давайте вычитать степени двойки : $$$2^0, 2^1, 2^2, ... 2^k$$$, пока $$$was$$$ не станет 0. Будем поддерживать флаг $$$Shift$$$ — был ли перенос битов в $$$n$$$ при вычитании какой — либо степени двойки. Пусть мы вычли на $$$k$$$-м шаге $$$2^k$$$ и количество битов стало равно $$$cnt_{new}$$$, а до вычитания было $$$cnt$$$, тогда рассмотрим два случая.
1) $$$cnt - cnt_{new} = 1$$$, тогда бит $$$k$$$ был включен в $$$n$$$ на $$$k$$$ — ом шаге, и если $$$Shift = false$$$, то прибавим к $$$ans$$$ — $$$2^k$$$, так как не было переноса битов, а значит бит k есть и в изначальном числе, и вычтем из $$$was$$$ — $$$1$$$. Если $$$Shift = true$$$, то мы этот бит добавили при предыдущих операциях, и его учитывать не нужно.
2) $$$cnt - cnt_{new} \neq 1$$$, тогда мы знаем, что кол-во битов не уменьшилось, также, что в числе $$$n$$$ нашелся такой бит $$$m$$$, что $$$2^m > 2^k$$$, и при этом бит $$$m$$$ есть в $$$n$$$. Причем $$$m - k - 1 = cnt_{new} - cnt$$$. Значит $$$m = k + 1 + cnt_{new} - cnt$$$. Давайте прибавим к ответу $$$2^m$$$, вычтем из $$$was$$$ — $$$1$$$ и присвоим флагу $$$Shift$$$ значение $$$true$$$, так как был перенос битов.
Таким образом, мы нашли изначальное число $$$n$$$, которое равно $$$ans$$$, а также сделали не более $$$O(log_2(n))$$$ запросов, так как $$$k \le log_2(n)$$$.
Таким образом, решение тратит не более 30 запросов, что укладывается в ограничения задачи.
t = int(input())
def ask (x):
print('-', x)
return int(input())
for i in range(t):
cur = int(input())
add = 0
ans = 0
while cur > 0:
x = ask(add + 1)
back = x - cur + 1
add = 2 ** back - 1
ans += 2 ** back
cur = x - back
print('!', ans)
#include <iostream>
using namespace std;
int ask (int x) {
cout << "- " << x << endl;
if (x == -1)
exit(0);
cin >> x;
return x;
}
int main() {
int t;
cin >> t;
while (t--) {
int cnt;
cin >> cnt;
int n = 0;
int was = 0;
while (cnt > 0) {
n += 1;
int nw = ask(1 + was);
int back = nw - cnt + 1;
n += (1 << back) - 1;
was = (1 << back) - 1;
cnt = nw - back;
}
cout << "! " << n << endl;
}
}
1780E - Josuke and Complete Graph
Идея: IzhtskiyTimofey
Подготовка: IzhtskiyTimofey
Разбор: IzhtskiyTimofey
Давайте зафиксируем $$$g$$$ и проверим, что ребро веса $$$g$$$ существует в $$$G'$$$. Первое число, которое делится на $$$g$$$, начиная с $$$L$$$ — $$$\lceil \frac{L}{g} \rceil \cdot g$$$, а второе — $$$(\lceil \frac{L}{g} \rceil + 1) \cdot g$$$, заметим что их $$$gcd$$$ равен $$$g$$$, то есть ребро между этими вершинами имеет вес $$$g$$$. Если второе число больше $$$R$$$, то ребра веса $$$g$$$ в графе $$$G'$$$ не существует, потому что на отрезке с $$$L$$$ по $$$R$$$ максимум только одна вершина, которая делится на $$$g$$$. То есть надо посчитать количество таких $$$g$$$, что $$$(\lceil \frac{L}{g} \rceil + 1) \cdot g \leq R$$$.
Рассмотрим $$$g \geq L$$$, тогда $$$(\lceil \frac{L}{g} \rceil + 1) \cdot g = 2 \cdot g$$$. Получаем верхнее ограничение на $$$g \leq \lfloor \frac{R}{2} \rfloor$$$. То есть $$$L \leq g \leq \lfloor \frac{R}{2} \rfloor$$$ — удовлетворяют.
Остались $$$g < L$$$.
Заметим, что $$$\lceil \frac{L}{g} \rceil$$$ принимает $$$O(\sqrt{L})$$$ значений. Тогда зафиксируем какое-то $$$f = \lceil \frac{L}{g} \rceil$$$, заметим, что $$$f$$$ соответствует последовательный отрезок значений $$$l \leq g \leq r$$$. Будем перебирать такие отрезки, поскольку их столько же, сколько и различных значений $$$f$$$, то есть $$$O(\sqrt{L})$$$. Тогда, если есть левая граница отрезка $$$l$$$, можно найти $$$r$$$ либо бинарным поиском, либо расписать формулу. Следующая левая граница будет просто $$$r + 1$$$. Тогда заметим, что если зафиксировано $$$f$$$, то $$$(f + 1) \cdot g \leq R$$$ равноценно $$$g \leq \lfloor \frac{R}{f + 1} \rfloor$$$. То есть при фиксированном отрезке с $$$l$$$ по $$$r$$$, $$$g$$$ удовлетворяет ограничению $$$l \leq g \leq min(r, \lfloor \frac{R}{f + 1} \rfloor)$$$. Тогда переберем все такие отрезки и просуммируем по ним хорошие $$$g$$$.
Тогда получается решение за $$$O(\sqrt{L})$$$ или $$$O(\sqrt{L} \cdot log(L))$$$, что, если аккуратно написать, тоже проходит.
def solve():
L, R = map(int, input().split())
ans = max(0, R // 2 - L + 1)
left = 1
while left < L:
C = (L + left - 1) // left
right = (L + C - 2) // (C - 1) - 1
ans += max(0, min(right, R // (C + 1)) - left + 1)
left = right + 1
print(ans)
t = int(input())
for test in range(t):
solve()
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
for (int test_case = 0; test_case < t; test_case++){
ll L, R;
cin >> L >> R;
ll ans = max(0ll, R / 2 - L + 1);
for (ll left = 1, right; left < L; left = right + 1){
ll C = (L + left - 1) / left;
right = (L + C - 2) / (C - 1) - 1;
ans += max(0ll, min(right, R / (C + 1)) - left + 1);
}
cout << ans << '\n';
}
}
Идея: AndreyPavlov
Подготовка: AndreyPavlov
Разбор: qualdoom
Отсортируем массив и будем обрабатывать тройки $$$i, j, k$$$, считая что $$$i < j < k$$$ и $$$a_i < a_j < a_k$$$. Теперь если $$$gcd(a_i, a_k) = 1$$$, то количество способов взять индекс $$$j$$$ равно $$$k - i - 1$$$.
Будем считать ответ на задачу для каждого $$$k$$$ от $$$1$$$ до $$$n$$$, считая что $$$a_k$$$ — максимальное число в тройке. Теперь пусть $$$c$$$ — количество чисел, взаимно простых с $$$a_k$$$ на префиксе от $$$1$$$ до $$$k - 1$$$, а $$$sum$$$ — сумма их индексов. Тогда к ответу нужно прибавить $$$c \cdot i - sum - c$$$.
Осталось узнавать количество чисел, взаимно простых с $$$a_k$$$ и сумму их индексов. Это можно делать с помощью метода включений и исключений. Пусть $$$cnt_i$$$ — количество чисел $$$a_j$$$, которые делятся на $$$i$$$, $$$s_i$$$ — сумма индексов $$$j$$$ чисел $$$a_j$$$, которые делятся на $$$i$$$. Посмотрим на простые числа $$$p_1, p_2, ..., p_m$$$, входящие в факторизацию числа $$$a_k$$$.
Тогда пусть изначально $$$c$$$ равно количеству чисел на префиксе, а $$$sum$$$ сумме индексов на префиксе. Заметим, что тогда мы учли лишние элементы — числа, которые делятся на $$$p_1, p_2, ..., p_m$$$, так как они будут не взаимно просты с $$$a_k$$$, вычтем их из $$$c$$$ и $$$sum$$$. Но сделав это мы опять же учли лишние элементы, кратные числам вида $$$p_i * p_j$$$, где $$$i \neq j$$$, прибавим их обратно и т.д. Таким образом мы можем перебрать маску $$$mask$$$ простых чисел $$$p_1, p_2, ..., p_m$$$. И в зависимости от четности битов в маске будем вычитать или прибавлять элементы, кратные $$$d$$$, , где $$$d$$$ — произведение простых, входящих в $$$mask$$$. Получив $$$c$$$ и $$$sum$$$ мы можем пересчитать ответ для позиции $$$i$$$.
Чтобы перейти от позиции $$$i$$$ к позиции $$$i+1$$$, обновим значения $$$cnt$$$ и $$$s$$$, добавив элемент $$$a_{i-1}$$$ с помощью перебора маски простых элемента $$$a_{i-1}$$$.
#include "bits/stdc++.h"
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
#define sz(v) ((int)(v).size())
#define all(a) (a).begin(), (a).end()
#define rall(a) a.rbegin(), a.rend()
#define F first
#define S second
#define pb push_back
#define ppb pop_back
#define eb emplace_back
#define time ((double)clock() / (double)CLOCKS_PER_SEC)
using pii = pair<int, int>;
using ll = long long;
using int64 = long long;
using ld = double;
const ll infll = (ll) 1e18 + 27;
const ll inf = (ll) 1e9;
#define dbg(x) cout << #x << " = " << (x) << endl
template<class T>
using pq = priority_queue<T, vector<T>, less<T>>;
template<class T>
using pqr = priority_queue<T, vector<T>, greater<T>>;
template<typename T, typename T2>
istream &operator>>(istream &in, pair<T, T2> &b) {
in >> b.first >> b.second;
return in;
}
template<typename T, typename T2>
ostream &operator<<(ostream &out, const pair<T, T2> &b) {
out << "{" << b.first << ", " << b.second << "}";
return out;
}
template<typename T>
istream &operator>>(istream &in, vector<T> &b) {
for (auto &v : b) {
in >> v;
}
return in;
}
template<typename T>
ostream &operator<<(ostream &out, vector<T> &b) {
for (auto &v : b) {
out << v << ' ';
}
return out;
}
template<typename T>
ostream &operator<<(ostream &out, deque<T> &b) {
for (auto &v : b) {
out << v << ' ';
}
return out;
}
template<typename T>
void print(T x, string end = "\n") {
cout << x << end;
}
template<typename T1, typename T2>
bool chkmin(T1 &x, const T2 &y) { return x > y && (x = y, true); }
template<typename T1, typename T2>
bool chkmax(T1 &x, const T2 &y) { return x < y && (x = y, true); }
mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
const int N = 3e5 + 10;
ll s[N];
ll cnt[N];
ll d[N][20];
int ptr[N];
bool u[N];
ll Cnt = 0;
ll Sum = 0;
ll Ans = 0;
void Answer (int x, int pos) {
ll C = Cnt;
ll X = Sum;
int K = (1ll << ptr[x]);
for (int mask = 1; mask < K; mask++) {
ll k = 1;
for (int j = 0; j < ptr[x]; j++) {
if ((mask >> j) & 1) {
k *= d[x][j];
}
}
int bits = __builtin_popcount(mask);
int D = k;
if (bits % 2 == 1) {
C -= cnt[D];
X -= s[D];
} else {
C += cnt[D];
X += s[D];
}
}
Ans += C * pos - X;
}
void add (int x, int pos) {
Cnt += 1;
Sum += pos + 1;
auto v = d[x];
int K = (1ll << ptr[x]);
for (int mask = 1; mask < K; mask++) {
ll k = 1;
for (int j = 0; j < ptr[x]; j++) {
if ((mask >> j) & 1) {
k *= d[x][j];
}
}
int D = k;
s[D] += pos + 1;
cnt[D] += 1;
}
}
void solve() {
for (int i = 2; i < N; i++) {
if (!u[i]) {
for (int j = i; j < N; j += i) {
u[j] = true;
d[j][ptr[j]] = i;
ptr[j]++;
}
}
}
int n;
cin >> n;
vector<int> a(n);
cin >> a;
sort(all(a));
for (int i = 0; i < n; i++) {
Answer(a[i], i);
if (i > 0) {
add(a[i - 1], i - 1);
}
}
cout << Ans << "\n";
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}
Идея: IzhtskiyTimofey
Подготовка: IzhtskiyTimofey, AndreyPavlov
Разбор: IzhtskiyTimofey, AndreyPavlov
Эта задача имеет несколько решений, использующих разные суффиксные структуры. Мы расскажем два из них — использующее суффиксный массив, и использующее суффиксный автомат.
Для начала построим суффиксный массив $$$suf$$$ и массив $$$lcp$$$ (наибольших общих префиксов) на строке $$$s$$$. Зафиксируем какое-то $$$k > 1$$$ и будем рассматривать все подстроки строки $$$s$$$ длины $$$k$$$. Сопоставим $$$1$$$ позициям $$$i$$$ массива $$$lcp$$$, таким что $$$lcp_i \geq k$$$, а остальным позициям $$$0$$$. Единица в позиции $$$i$$$ означает, что подстроки длины $$$k$$$, начинающиеся $$$suf_i$$$ и $$$suf_{i + 1}$$$, равны. Рассмотрим какой-то блок длины $$$len$$$ из единиц, тогда для $$$len + 1$$$ подстрок длины $$$k$$$ количество вхождений в $$$s$$$ — $$$len + 1$$$, тогда чтобы подстроки в этом блоке были вкусными, надо, чтобы $$$len + 1$$$ делилось на $$$k$$$.
Будем перебирать $$$k$$$ от $$$n$$$ до $$$2$$$ и поддерживать все размеры блоков. Тогда, при переходе к новому $$$k$$$ необходимо поддерживать события — изменить $$$0$$$ на $$$1$$$, в таких $$$i$$$, что $$$lcp_i = k$$$. Чтобы это делать, можно поддерживать СНМ. Тогда, когда мы знаем для каждого размера — количество блоков с таким размером, достаточно рассмотреть все блоки длины $$$len$$$, такие что $$$len + 1$$$ — делитель $$$k$$$. Это можно делать явно, перебирая $$$k$$$, $$$2 \cdot k$$$, ..., поскольку, это будет работать за сумму гармонического ряда.
Для $$$k = 1$$$, очевидно, что любые подстроки длины $$$1$$$ подходят, поэтому можно просто добавить к ответу $$$n$$$. Итоговая асимптотика $$$O(n \cdot log(n))$$$
Построим сам суффиксный автомат, теперь насчитаем для каждой вершины суффиксного автомата динамику $$$dp_v$$$ — это количество путей из вершины $$$v$$$ в терминальные вершины. Эта динамика означает количество вхождений подстроки, соответствующей этой вершине, во всю строку. Введём функцию $$$f(v)$$$ — длина самой длинной подстроки ведущей в вершину $$$v$$$. Мы знаем, что в вершину $$$v$$$ суффиксного автомата ведут все подстроки длиной от $$$l_v$$$ до $$$r_v$$$ — каждая единожды. Где $$$r_v = f(v)$$$, а $$$l_v = f(suff_v) + 1$$$, где $$$suff_v$$$ — суффиксная ссылка вершины $$$v$$$. Почему это так? В вершину $$$v$$$ суффиксного автомата ведут все подстроки вида $$$s[x:k], s[x+1:k], ..., s[y:k]$$$, а есть суффиксная ссылка $$$suff_v$$$, в которую ведут все подстроки вида $$$s[x + 1:k], s[y + 2:k], ..., s[t: k]$$$.
Для того чтобы решить задачу переберём вершину $$$v$$$ и посмотрим на количество вхождений любой подстроки которая ведёт в вершину $$$v$$$ — $$$dp_v$$$, тогда зафиксируем $$$c$$$ — количество таких $$$l_v \le x \le r_v$$$, что $$$dp_v$$$ делится нацело на $$$x$$$. Следовательно к ответу нужно прибавить $$$dp_v \cdot c$$$. Все делители можно сохранить за $$$O(n \cdot log(n))$$$ и каждый раз искать бинпоиском количество таких $$$x$$$.
Асимптотика $$$O(n \cdot log(n))$$$
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> suffix_array(string s){
int n = s.size();
vector<int> a(n), c(n), h(n);
vector<pair<char, int>> t;
for (int i = 0; i < n; i++) t.push_back({s[i], i});
sort(t.begin(), t.end());
int cur = -1;
for (int i = 0; i < n; i++){
if (i == 0 || t[i].first != t[i - 1].first){
cur++;
h[cur] = i;
}
a[i] = t[i].second;
c[a[i]] = cur;
}
vector<int> a1(n), c1(n);
for (int len = 1; len < n; len *= 2){
for (int i = 0; i < n; i++){
int j = (n + a[i] - len) % n;
a1[h[c[j]]++] = j;
}
a = a1;
cur = -1;
for (int i = 0; i < n; i++){
if (i == 0 || c[a[i]] != c[a[i - 1]] || c[(a[i] + len) % n] != c[(a[i - 1] + len) % n]){
cur++;
h[cur] = i;
}
c1[a[i]] = cur;
}
c = c1;
}
return a;
}
vector<int> build_lcp(string s, vector<int> suf){
int n = s.size();
vector<int> rsuf(n), lcp(n);
for (int i = 0; i < n; i++) rsuf[suf[i]] = i;
int cur = 0;
for (int i = 0; i < n; i++){
int j = rsuf[i];
if (j != n - 1){
while (s[suf[j] + cur] == s[suf[j + 1] + cur]) cur++;
lcp[j] = cur;
}
if (cur > 0) cur--;
}
return lcp;
}
const int N = 1e6 + 1;
int r[N], l[N], us[N], cnt[N];
vector<int> pos[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int n;
cin >> n;
string s;
cin >> s;
s += '$';
vector<int> suf = suffix_array(s);
vector<int> lcp = build_lcp(s, suf);
for (int i = 0; i < lcp.size(); i++) {
pos[lcp[i]].push_back(i);
}
ll ans = n;
for (int k = n; k >= 2; k--) {
for (int i : pos[k]) {
// add i
us[i] = true;
cnt[1]++;
l[i] = r[i] = i;
if (i != 0 && us[i - 1]) {
cnt[i - l[i - 1]]--;
cnt[1]--;
cnt[i - l[i - 1] + 1]++;
l[i] = l[i - 1];
r[l[i - 1]] = i;
}
if (i + 1 < lcp.size() && us[i + 1]) {
cnt[r[i + 1] - i]--;
cnt[i - l[i] + 1]--;
cnt[r[i + 1] - l[i] + 1]++;
l[r[i + 1]] = l[i];
r[l[i]] = r[i + 1];
}
}
for (int x = k; x <= n; x += k) {
ans += 1ll * x * cnt[x - 1];
}
}
cout << ans << "\n";
}
/* Includes */
#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
/* Using libraries */
using namespace std;
/* Defines */
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ld long double
#define pb push_back
#define vc vector
#define sz(a) (int)a.size()
#define forn(i, n) for (int i = 0; i < n; ++i)
#define pii pair <int, int>
#define vec pt
#define all(a) a.begin(), a.end()
const int K = 26;
const int N = 1e6 + 1;
struct node {
int next[K];
int suf = -1, pr = -1, dp = 0, len = 0, ch = -1;
node () {
forn (i, K) next[i] = -1;
}
};
int get (char c) {
if (c >= 'a')
return c - 'a';
return c - 'A';
}
int lst = 0, sz = 1;
node t[N * 2];
int used[N * 2];
int add (int a, int x) {
int b = sz++;
t[b].pr = a;
t[b].suf = 0;
t[b].ch = x;
for (; a != -1; a = t[a].suf) {
if (t[a].next[x] == -1) {
t[a].next[x] = b;
t[b].len = max(t[b].len, t[a].len + 1);
continue;
}
int c = t[a].next[x];
if (t[c].pr == a) {
t[b].suf = c;
break;
}
int d = sz++;
forn (i, K) t[d].next[i] = t[c].next[i];
t[d].suf = t[c].suf;
t[c].suf = t[b].suf = d;
t[d].pr = a;
t[d].ch = x;
for (; a != -1 && t[a].next[x] == c; a = t[a].suf) {
t[a].next[x] = d;
t[d].len = max(t[d].len, t[a].len + 1);
}
break;
}
return b;
}
void add (char c) {
lst = add(lst, get(c));
}
void dfs (int u) {
used[u] = 1;
for (int i = 0; i < K; ++i) {
if (t[u].next[i] == -1) continue;
int v = t[u].next[i];
if (!used[v])
dfs(v);
t[u].dp += t[v].dp;
}
}
vc <int> p[N], pr;
int dr[N];
vc <pii> d;
int l, r, cur = 0;
int cnt_log (int x, int y) {
int z = 1, res = 0;
while (y >= z) {
z *= x;
++res;
}
return res - 1;
}
void rec (int i, int x) {
if (i == sz(d)) {
cur += l <= x;
return;
}
rec(i + 1, x);
for (int j = 1; j <= d[i].second; ++j) {
x *= d[i].first;
if (x > r)
break;
rec(i + 1, x);
}
}
void solve () {
int n;
cin >> n;
string s;
cin >> s;
for (char c : s)
add(c);
for (int a = lst; a != -1; a = t[a].suf)
t[a].dp = 1;
dfs(0);
for (int i = 2; i <= n; ++i) {
if (dr[i] == 0) {
dr[i] = i;
pr.pb(i);
}
for (int j = 0; j < sz(pr) && pr[j] <= dr[i] && i * pr[j] <= n; ++j)
dr[i * pr[j]] = pr[j];
}
long long ans = 0;
forn (i, sz) {
if (t[i].len == 0) continue;
l = t[t[i].suf].len + 1;
r = t[i].len;
int x = t[i].dp;
d.clear();
while (x > 1) {
int y = dr[x];
if (d.empty() || d.back().first != y)
d.pb({y, 1});
else
d.back().second++;
x /= y;
}
rec(0, 1);
ans += t[i].dp * cur;
cur = 0;
}
cout << ans << '\n';
}
/* Starting and precalcing */
signed main() {
/* freopen("input.txt","r",stdin);freopen("output.txt","w",stdout); */
fast;
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}
Ну и где решение C? Очень хочется узнать решение NP-сложной задачки :D
Can't wait for the solution of C. Show us guys, how to solve NP-hard problems!
Hahahahahahahaha you're so funny hahahahhaha
Maybe it is P but not O(n^2).
Prove P=NP to solve it
Not my duty, lol
How come I see ACs still on C? No hacks were made on the problem?
Has no one made a hack for C yet?
The tester code probably uses the same faulty algorithm so it would be to no avail.
The author's solution is wrong. Therefore, any hack would still get AC, even if the output is incorrect.
Problem D was very interesting :) ,one mistake and whole efforts of problemsetters and testers got ruined.
I thought D was easier than B. Although I kinda over complicated B for no reason.
Weren't the incorrect greedy solutions for C O(n)? Why was the constraint on the problem O(n^2) then?
Weren't the incorrect greedy solutions for C O(n)? Why was the constraint on the problem O(n^2) then?
I think it was to allow solutions that did not use priority_queue or something similar
I don't understand why problem C was unsolvable?
this is my code please give me a counterexample.
On the last row of Tutorial of B:
"Let $$$s$$$ be the array $$$a$$$"
should probably be
"Let $$$s$$$ be the sum of the array $$$a$$$"
They probably used machine translation. The solution to E is impenetrable.
delete
It's a bad idea because some poor people like me spent ~30min trying to solve it and ~20min trying to understand why so many people solved such a hard problem xd
delete
No
LOL. Some people solved C with incorrect solutions that they figured out within minutes and moved on. And those who realized that solution is incorrect will be punished. What kind of fairness is that?
problem E & F are so interesting. i enjoyed..
My solution failed system tests on C because it got a better result than the author's one, lol
Did you found any counter-test for your solution?
Yeah
They should have asked for the exact assignment instead of just the maximum value, so that they can check for a
FAIL
verdict correctly. (FYI,FAIL
is the verdict when the submission found a better solution than the jury's) They might have found the issue before the contest if this was the case.lol
how it should be 11 can u explain it bit more clearer...
There are 6 guests who likes the dish #1, and the remaining 5 likes the #2. So if we split the 6 guests in table #1 and #2, and the 5 who like #2 at table #3, all 11 guests will be happy.
Problem G is quite similar to this problem. I had to modify my solution for the Educational round problem a bit to get AC on this round's G.
A brief tutorial to problem E, for people like me who cannot follow the official one:
Value $$$x$$$ will appear in one of the edges iff: $$$L \leq px < (p+1)x \leq R$$$, where $$$p=ceil(\frac{L}{x})$$$.
Now we enumerate every value of $$$p$$$ and count the number of possible $$$x$$$ for each $$$p$$$.
For $$$p=p_0$$$, the above inequality gives range of x: $$$\frac{L}{p_0} \leq x \leq \frac{R}{p_0+1}$$$.
Note that there is a hidden constraint of $$$ceil(\frac{L}{x}) = p_0$$$. This translates to $$$\frac{L}{p_0} \leq x < \frac{L}{p_0-1}$$$.
Combine the two ranges above, we get, for $$$p=p_0$$$, possible values of $$$x$$$ satisfies: $$$\frac{L}{p_0} \leq x \leq min(\frac{R}{p_0+1}, floor(\frac{L-1}{p_0-1}))$$$.
And we use sqrt decomposition to solve this counting problem: For $$$p\leq sqrt(L)+1$$$, we compute the range of $$$x$$$. For $$$p > sqrt(L)+1$$$, we have $$$x \leq sqrt(L)$$$, so we can just iterate through all $$$x$$$ values.
Complexity is $$$O(sqrt(L))$$$.
In C question greedy solution fail on test case-
1
11 3
1 1 1 1 1 1 2 2 2 2 2
5 4 2
correct answer for above testcase = 11, but greedy solution gives answer = 10
Can anyone explain what was the intended solution for C, which turned out to be incorrect.
Group people by what they like, and while there are groups of people and tables left, try to put the largest group on the largest table. If they don't fit, just use as many as you can and subtract that amount before deleting the table. If they do fit, delete the group of people and the table. "Answer" is however many people this process gives a table. The original might've been slightly different, but this is the silly wrong solution I got AC with.
In
Problem D
, in 2nd Tutorial (by qualdoom), for the condition (pt.2) where "$$$cnt-cnt_{new}\not=1$$$", can someone kindly explain the part, how this below equation is formed?$$$m - k - 1 = cnt_{new} - cnt$$$
Consider the real number is 24 its binary representation is
11000
, and you need to guess this number. also, you can't subtract a number greater than the real number so if we subtracted 1 from real number which was 24, we will have 23 which its binary representation is10111
so the number of unit bits has been changed and become 4-unit bits instead of 2 how this happened? hence, we now have 23 which has 4-unit bits and previous has 2 so the LSB at index (4-2+1) 0-based we add1<<lsbIndex
to obtain the real number. I hope that helped you.Who can explain me, how to use mobius function in problem F?
When you want to get $$$f(d) = \#func(a, b)$$$ where $$$gcd(a, b) = d$$$. You can count $$$g(d) = \#func(a, b)$$$ where $$$d | a$$$ and $$$d | b$$$.
Then $$$f(d) = \sum_{i=1}^n g(i * d) * \mu(i)$$$
Where $$$\mu(x)$$$ is the mobius function.
Then you need to count for each number $$$k$$$ from 1 to max $$$a_i$$$, the number of triplets $$$(a_i, a_j, a_k)$$$ with $$$k | min(a_i, a_j, a_k)$$$ and $$$k | max(a_i, a_j, a_k)$$$.
Mobius, more like Morbius
Can you share some resources where I can study this?
these blogs are very useful:
https://codeforces.net/blog/entry/54090
https://codeforces.net/blog/entry/53925
but I got the main idea from this pdf
I don't know why. I want to comfort the author. qnq
Here goes an easier and short solution of F which does not involve Mobius or this inclusion-exclusion using masks and their parity
Can someone give a test case where this approach gives a wrong answer to C?
Calculate how many meals of each type and how many tables of each size there are.
Go through the meals, if there is a table with the same size as the count of that meal, then put those people to that table.
Put remaining meal and table counts to two priority queues. While there are still some empty tables or not all people has a spot: take the top of meals and put them at the biggest empty table, if some people who like that meal are still left, check if there is empty table with that amount of spots, if there is put them there, otherwise put that number back to priority queue.
Ok, here's a counterexample: tables are
2 2 3
and people are1 1 1 1 2 2 2
. The second step goes as no-op, so you will take ones into the third table (which has 3 seats) and then twos are placed in the remaining first/second table, which is not a correct strategy since you could have placed ones into first and second table and then remaining twos into the third table.My approach for D (similar to the second tutorial solution, it seems, but it doesn't explicitly need flags and might be easier to understand for some):
To determine whether the last bit is 0 or 1, we can simply subtract 1. If the last bit was a 1, then it becomes 0 and the $$$cnt$$$ decreases by exactly 1. Now that the last bit is already 0, we can check the second-to-last bit by subtracting 2. In general, if the last $$$k$$$ bits are set to 0 while the rest of the bits are unchanged from the original, we can test bit position $$$k$$$ (from the right) by subtracting $$$2^k$$$ and seeing if $$$cnt$$$ decreases by exactly 1.
But what happens when the bit at the position we're testing (let's say position $$$k$$$) is actually a 0? In that case, $$$cnt$$$ either stays the same or increases, so we know that this position originally has a 0. However, this attempted subtraction of $$$2^k$$$ ruins our desired pattern, because the bit at position $$$k$$$ changed from 0 to 1 and at least one bit on its left has changed. We would have wanted the bits from up to position $$$k$$$ to all be 0 and everything else unchanged in order to test the next bit, at position $$$k + 1$$$...
We can deal with this by "undoing" the latest undesirable subtraction by instead treating it as part of the next subtraction. Normally, the next subtraction is supposed to be $$$2^{k + 1}$$$, but since we already performed an undesirable subtraction of $$$2^k$$$, we simply subtract another $$$2^k$$$ to result in a overall subtraction of $$$2^{k + 1}$$$ as if the undesired subtraction never happened.
Note that there could be a sequence of undesirable subtractions, in which case, we just keep track of the total of the undesirable subtractions and treat them all as part of the next subtraction. Eventually, we would have to find a 1, which resolves all these undesirable subtractions. Once we find the MSB, the $$$cnt$$$ should become 0, at which point, we are done.
My submission: 190561881 ($$$acc$$$ is the accumulation of undesired subtractions that we are trying to undo)
Thank you for the explanation!!
Simple implementation for F 190544353
Can you explain your solution if it's different from the editorial?
I have similar solution. Mine is: calculate $$$dp[x]$$$ -- number of ways to choose a triple which value of gcd is $$$x$$$. To calculate amount of such triples for every $$$x$$$ sort an array then for every $$$x$$$ consider only numbers which are divisible by $$$x$$$, let their indices be $$$ind$$$, we should calculate sum over all $$$i < j$$$ of $$$ind_j - ind_i - 1$$$, we can calculate it by iterating over these indices storing sum of considered indices and their cnt. Then you have a $$$dp$$$ where you should substract from $$$dp[x]$$$ $$$dp[2 * x], dp[3 * x], ...$$$ to obtain correct answer.
Consider for g<sqrt(L) and g>sqrt(L) respectively, for the first situation there's at most sqrt(L) values of g, so ceil(L/g) will have at most sqrt(L) values. For the second situation, we have 1<=ceil(L/g)<L/g+1<L/sqrt(L)+1=sqrt(L)+1, so there's at most ceil(sqrt(L)) different values.
How to generate all values of ceil(L / i) where i belongs to [1, L] in O(sqrt(L))?
First let i = 1 to ceil(sqrt(L))-1. For the remaining values, for m = L/ceil(sqrt(L)) to 1, calculate the range where ceil(L/i)=m.
I did the same thing in problem B yet kept getting TLE. Can someone point out my mistake. Thankyou!
Please help !
cuml may not fit in 32bit integers
use long long, instead of long int. https://en.cppreference.com/w/cpp/language/types Long int's aren't always 64 bits-width, maybe that's a problem in your case.
On 32-bit compilers "long int" is same as "int", both of them are 32 bits. Use "long long" instead.
What is the time complexity in F and why is it quick? IMHO we have O(N * 2^(an average number of prime divisors)) so it doesn't seem like a quick solution.
lets think like this. you know the number of divisors of a number n is O(log(n)). now you are only iterating on SOME of these divisors.
Let $$$preres_x$$$ be the number of ways of choosing the triplets where the $$$gcd(a_i,b_j)$$$ is a multiple of $$$x$$$ and $$$res_x$$$ be the number of ways of choosing the triplets where $$$gcd(a_i,b_i)$$$ is exactly $$$x$$$. You can calculate array $$$res$$$ from $$$preres$$$. If you know the values of $$$res_y$$$ for all $$$y$$$ (where $$$y$$$ is a multiple of $$$x$$$) and $$$preres_x$$$, then you can calculate the value of $$$res_x$$$ and finally, $$$res_1$$$ will be the answer. You can do this by iterating from $$$3*10^5$$$ to $$$1$$$.
The time complexity is sum of harmonic sequence $$$\sum_{x = 1}^{N} \left \lfloor \frac{N}{x} \right \rfloor$$$ which is equal to $$$O(nlogn)$$$.
Of all the rounds this had to happen in a round full of Jojo's references
Can someone please tell me what was wrong with C? My approach to solving C was: Group all the guests having the same liking. Now assign the biggest group to the largest table. If some guests are still left, insert them in the priority queue and continue this way.
How was C an NP hard problem?
https://codeforces.net/blog/entry/111737?#comment-995960
Your approach is incorrect. Consider the following scenario:
If you assign the biggest group to the largest table, then the 4-table serves dish 1 (all four like it), one of the 3-tables serves dish 2 (all three like it), and the other 3-table serves dish 1 (two out of three like it), with one unsatisfied guest. But if you instead had both 3-tables serve dish 1 while the 4-table serves dish 2, then everyone would be satisfied.
ok Thanks for telling
Even though C couldn't be solved with given constraints during the contest I think it's better to lower constraints to make it solvable, write a proper solution and post the updated solution in the editorial, instead of completely removing it from the contest and archive. The problem is not bad at all, tbh.
It's NP-hard, which means it almost certainly cannot be solved in polynomial time. Constraints would require $$$n$$$ to be about $$$20$$$, or maybe even less! The brute-force solution would be incredibly dull. There may be heuristics to speed it up and allow a little higher constraints, but this is not suitable for CP.
Doesn't mean it can't be solved at all. Better to keep a modified version with extremely low constraints than to remove it completely.
Can anybody tell me "correct" solution of C? or at least some ideas
Can anybody tell me "correct" solution of C? or at least some ideas
I would surely become a specialist after this round (rank 16) but...... It's unrated! And problem G is kind of rigid that almost everyone who has learnt sam before can solve it.
But anyway,the problems are excellent!
can someone explain what's wrong with problem C. Instead of posting correct solution why authors completely removed problem C
There is no correct solution to that problem. It is a NP-hard problem which cannot be solved in polynomial time
D was quite confusing cuz I have never solve interactive problems lol. F was easier than normal :V.
I don't understand the tutorial for problem G. Can anyone explain the idea of it?
Does any one know how to calculate the time complexity of G? More detailedly,the time complexity of find the number of x,which is a factor of n, that l<=x<=r? The solution implied that is almost nlog(n) in total , but I can't understand why.
how do we get the root L bound in problem E. Can someone prove
Hi Sorry if my doubt is too silly
In this question, 1780B — GCD Partition. For the given testcase:
3
1 4 5
what is the value of k for this due to which maximum score of 5 is coming? like are we partioning this array?