#include <cstdio>
#include <vector>
#include <cmath>
#include <unordered_set>
#ifdef LOCAL
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#else
#define dbg(...)
#endif
using namespace std;
#ifdef LOCAL
constexpr int MAX_N=100'000;
#else
constexpr int MAX_N=10'000'000;
#endif
bool is_prime(const int n, const vector<int>& lower_primes) {
const int sqrt1 = sqrt(n);
// start with j=2 because we only check 6n-1, 6n+1, which are never divisible by 2 and 3
for (unsigned long j = 2; j < lower_primes.size(); ++j) {
if (lower_primes[j] > sqrt1) {
break;
}
if (n % lower_primes[j] == 0) {
return false;
}
}
return true;
}
vector<int> compute_primes(const int max_n) {
vector<int> primes;
primes.push_back(2);
primes.push_back(3);
for (int i = 6; i <= max_n; i += 6) {
int candidate_1 = i - 1;
if (is_prime(candidate_1, primes)) {
dbg("found prime %d\n", candidate_1);
primes.push_back(candidate_1);
}
int candidate_2 = i + 1;
if (is_prime(candidate_2, primes)) {
dbg("found prime %d\n", candidate_2);
primes.push_back(candidate_2);
}
}
return primes;
}
vector<int> factorize(int n, vector<int>& primes) {
dbg("Factorizing %d\n", n);
vector<int> fact;
for (const int prime: primes) {
while (n % prime == 0) {
fact.push_back(prime);
n /= prime;
}
if (n == 1) break;
}
if (n != 1) fact.push_back(n);
dbg("Found %lu prime factors\n", fact.size());
return fact;
}
unordered_set<int> kamyki;
int kamyki_modulo[MAX_N];
int score_for_jumpsize(const int k) {
int max_score = 0;
for (auto& kamyk: kamyki) {
const int m = kamyk % k;
kamyki_modulo[m]++;
if (kamyki_modulo[m] > max_score) {
max_score = kamyki_modulo[m];
}
}
// zero the array
if (static_cast<int>(kamyki.size()) > k) {
for (int i = 0; i < k; ++i) {
kamyki_modulo[i] = 0;
}
} else {
for (auto& kamyk: kamyki) {
const int m = kamyk % k;
kamyki_modulo[m] = 0;
}
}
return max_score;
}
int get_max_relevant_num(const int n_size, const int min_score) {
// highest number that can get score min_score on board of size n_size
return (n_size-1)/(min_score-1);
}
vector<int> primes_to_consider;
int main() {
vector<int> primes = compute_primes(MAX_N);
dbg("Found %lu primes, last one one %d\n\n", primes.size(), primes.back());
int n, p;
int kamycount = 0;
int prevscore = 0;
scanf("%d %d", &n, &p);
for (int pi = 0; pi < p; ++pi) {
int newkamyk;
scanf("%d", &newkamyk);
if (kamyki.contains(newkamyk)) {
kamyki.erase(newkamyk);
kamycount -= 1;
} else {
kamyki.insert(newkamyk);
kamycount += 1;
}
if (kamycount < 3) {
if (kamycount == 2) {
dbg("Need to check if stones are adjacent...\n");
vector<int> ks;
for (auto& kamyk: kamyki) {
ks.push_back(kamyk);
}
if (ks[0] == ks[1] + 1 || ks[0] == ks[1] - 1) {
printf("1\n");
prevscore = 1;
continue;
}
}
dbg("Small count = trivial answer\n");
prevscore = kamycount;
printf("%d\n", kamycount);
continue;
}
// kamycount >= 3
int min_score = (kamycount + 1) / 2; // when choosing k=2, we get either all odd or all even
int max_relevant_num = get_max_relevant_num(n, min_score+1); // k higher than that get less than min_score jumps
dbg("min score = %d\n", min_score);
dbg("max relevant num = %d\n", max_relevant_num);
for (unsigned long j = 0; j < primes.size(); ++j) {
if (primes[j] <= max_relevant_num) {
const int score = score_for_jumpsize(primes[j]);
dbg("Score for prime %d: %d\n", primes[j], score);
if (score == prevscore + 1) {
min_score = score;
break;
}
if (score > min_score) {
min_score = score;
max_relevant_num = get_max_relevant_num(n, min_score+1);
}
} else {
dbg("Prime %d was too big to attain score of over %d\n", primes[j], min_score);
break;
}
}
printf("%d\n", min_score);
prevscore = min_score;
}
return 0;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | #include <cstdio> #include <vector> #include <cmath> #include <unordered_set> #ifdef LOCAL #define dbg(...) fprintf(stderr, __VA_ARGS__) #else #define dbg(...) #endif using namespace std; #ifdef LOCAL constexpr int MAX_N=100'000; #else constexpr int MAX_N=10'000'000; #endif bool is_prime(const int n, const vector<int>& lower_primes) { const int sqrt1 = sqrt(n); // start with j=2 because we only check 6n-1, 6n+1, which are never divisible by 2 and 3 for (unsigned long j = 2; j < lower_primes.size(); ++j) { if (lower_primes[j] > sqrt1) { break; } if (n % lower_primes[j] == 0) { return false; } } return true; } vector<int> compute_primes(const int max_n) { vector<int> primes; primes.push_back(2); primes.push_back(3); for (int i = 6; i <= max_n; i += 6) { int candidate_1 = i - 1; if (is_prime(candidate_1, primes)) { dbg("found prime %d\n", candidate_1); primes.push_back(candidate_1); } int candidate_2 = i + 1; if (is_prime(candidate_2, primes)) { dbg("found prime %d\n", candidate_2); primes.push_back(candidate_2); } } return primes; } vector<int> factorize(int n, vector<int>& primes) { dbg("Factorizing %d\n", n); vector<int> fact; for (const int prime: primes) { while (n % prime == 0) { fact.push_back(prime); n /= prime; } if (n == 1) break; } if (n != 1) fact.push_back(n); dbg("Found %lu prime factors\n", fact.size()); return fact; } unordered_set<int> kamyki; int kamyki_modulo[MAX_N]; int score_for_jumpsize(const int k) { int max_score = 0; for (auto& kamyk: kamyki) { const int m = kamyk % k; kamyki_modulo[m]++; if (kamyki_modulo[m] > max_score) { max_score = kamyki_modulo[m]; } } // zero the array if (static_cast<int>(kamyki.size()) > k) { for (int i = 0; i < k; ++i) { kamyki_modulo[i] = 0; } } else { for (auto& kamyk: kamyki) { const int m = kamyk % k; kamyki_modulo[m] = 0; } } return max_score; } int get_max_relevant_num(const int n_size, const int min_score) { // highest number that can get score min_score on board of size n_size return (n_size-1)/(min_score-1); } vector<int> primes_to_consider; int main() { vector<int> primes = compute_primes(MAX_N); dbg("Found %lu primes, last one one %d\n\n", primes.size(), primes.back()); int n, p; int kamycount = 0; int prevscore = 0; scanf("%d %d", &n, &p); for (int pi = 0; pi < p; ++pi) { int newkamyk; scanf("%d", &newkamyk); if (kamyki.contains(newkamyk)) { kamyki.erase(newkamyk); kamycount -= 1; } else { kamyki.insert(newkamyk); kamycount += 1; } if (kamycount < 3) { if (kamycount == 2) { dbg("Need to check if stones are adjacent...\n"); vector<int> ks; for (auto& kamyk: kamyki) { ks.push_back(kamyk); } if (ks[0] == ks[1] + 1 || ks[0] == ks[1] - 1) { printf("1\n"); prevscore = 1; continue; } } dbg("Small count = trivial answer\n"); prevscore = kamycount; printf("%d\n", kamycount); continue; } // kamycount >= 3 int min_score = (kamycount + 1) / 2; // when choosing k=2, we get either all odd or all even int max_relevant_num = get_max_relevant_num(n, min_score+1); // k higher than that get less than min_score jumps dbg("min score = %d\n", min_score); dbg("max relevant num = %d\n", max_relevant_num); for (unsigned long j = 0; j < primes.size(); ++j) { if (primes[j] <= max_relevant_num) { const int score = score_for_jumpsize(primes[j]); dbg("Score for prime %d: %d\n", primes[j], score); if (score == prevscore + 1) { min_score = score; break; } if (score > min_score) { min_score = score; max_relevant_num = get_max_relevant_num(n, min_score+1); } } else { dbg("Prime %d was too big to attain score of over %d\n", primes[j], min_score); break; } } printf("%d\n", min_score); prevscore = min_score; } return 0; } |
English