Codeforces 1622F - Quadratic Set (find property + hash)

Posted by srhino on Wed, 05 Jan 2022 10:33:16 +0100

A real educational hot tea.

First, let's see the preliminary transformation of the problem: we first find \ (\ prod \ limits {I = 1} ^ n (I!) \) In the prime factor decomposition form of, all prime numbers with odd occurrences are extremely easy to handle - because \ (\ prod \ limits {I = 1} ^ n (I!)= \prod\limits_{i=1}^ni ^ {n-i + 1} \), so the times of \ (n-1,n-3,\cdots,n\bmod 2+1 \) in the formula are even, and we can kick them out. Therefore, in the \ (\ prod \ limits {I = 1} ^ Ni! \) prime factor decomposition form, the set of prime factors with odd occurrences is equal to the set of prime factors with odd occurrences in \ (n!! \), After preprocessing the minimum prime factor of each number, it can be decomposed \ (n\log n \).

So the problem is to find a sequence with the smallest length \ (\ {a_m \} \), which satisfies \ (1\le a_i\le n \), and in the prime factor decomposition form of \ (\ prod \ limits {I = 1} ^ ma_i! \), the set of prime factors with odd occurrences is equal to the set of prime factors with odd occurrences of \ (n!! \). Here, we might as well discover the following properties: if \ (n \) is an even number, then \ (n!!=2^{n/2} · (\ dfrac{n}{2})! \), The former module of prime number \ (2 \) is followed by either \ (2 ^ 0 \) or \ (2 ^ 1 \), so the set with \ (n!! \) prime factor of odd number is either the same as \ (\ dfrac{n}{2})! \) Same as \ (2 · (\ dfrac{n}{2})! \) Same; Similarly, if \ (n \) is an odd number, then \ (n!!=\dfrac{n!}{(n-1)!!}=\dfrac{n!}{2^{(n-1)/2}·(\frac{n-1}{2})!}\)， Therefore, for odd numbers \ (n \), \ (n!! \) sets with odd occurrences are either the same as \ (n! · (\ dfrac{n-1}{2})! \) Same as \ (2 · n! · (\ dfrac{n-1}{2})! \) Same.

That is, the length of the sequence \ ({a_m} \) with the smallest length that meets the condition shall not exceed \ (3 \). Therefore, we consider solving the cases of \ (0,1,2 \) separately. We can directly judge the case of \ (0 \), and consider hashing for the case of \ (1 \). We assign a random weight of \ ([1,2 ^ {64}-1] \) to each quality factor, and then define the weight of a set as the XOR of the weight of all elements in it. In this way, after preprocessing the weight of \ (1!,2!,\cdots,n! \), Check whether the weight of a \ (i! \) is equal to the weight of \ (n!! \). The same is true for \ (2 \). The position of each weight in map preprocessing can be used.

Time complexity \ (n\log n \).

mt19937 rng(20060729 ^ chrono :: steady_clock :: now().time_since_epoch().count());
template<typename T> T rand(T l, T r) {return uniform_int_distribution<T>(l, r)(rng);}
const int MAXN = 1e6;
int n, pr[MAXN / 2 + 5], prcnt = 0, vis[MAXN + 5], mnp[MAXN + 5];
int cnt[MAXN + 5], book[MAXN + 5];
u64 v[MAXN + 5], pre[MAXN + 5];
void sieve(int n) {
for (int i = 2; i <= n; i++) {
if (!vis[i]) pr[++prcnt] = i, mnp[i] = i;
for (int j = 1; j <= prcnt && pr[j] * i <= n; j++) {
vis[pr[j] * i] = 1; mnp[pr[j] * i] = pr[j];
if (i % pr[j] == 0) break;
}
}
}
int main() {
scanf("%d", &n); sieve(MAXN);
for (int i = 1; i <= n; i++) if ((n - i + 1) & 1) {
int tmp = i;
while (tmp ^ 1) {
int p = mnp[tmp];
while (tmp % p == 0) tmp /= p, cnt[p] ^= 1;
}
}
bool flg = 1;
for (int i = 1; i <= n; i++) flg &= (!cnt[i]);
if (flg) {
printf("%d\n", n);
for (int i = 1; i <= n; i++) printf("%d%c", i, " \n"[i == n]);
return 0;
}
for (int i = 1; i <= n; i++) v[i] = rand(1ull, ULLONG_MAX);
u64 hs = 0;
for (int i = 1; i <= n; i++) if (cnt[i]) hs ^= v[i];
for (int i = 1; i <= n; i++) {
pre[i] = pre[i - 1]; int tmp = i;
while (tmp ^ 1) {
int p = mnp[tmp];
while (tmp % p == 0) tmp /= p, pre[i] ^= v[p];
}
}
for (int i = 1; i <= n; i++) if (pre[i] == hs) {
printf("%d\n", n - 1);
for (int j = 1; j <= n; j++) if (j != i) printf("%d ", j);
return 0;
}
unordered_map<u64, int> pos;
for (int i = 1; i <= n; i++) {
if (pos[pre[i] ^ hs]) {
int X = i, Y = pos[pre[i] ^ hs];
printf("%d\n", n - 2);
for (int i = 1; i <= n; i++) if (i != X && i != Y)
printf("%d ", i);
return 0;
}
pos[pre[i]] = i;
}
printf("%d\n", n - 3);
for (int i = 1; i <= n; i++) if (i != 2 && i != (n >> 1) && i != n)
printf("%d ", i);
return 0;
}