квадратные подмножества
Условие
Дан массив длины . . Необходимо вычислить количество различных способов выбрать некоторое непустое подмножество его элементов так, чтобы их произведение было равно квадрату некоторого натурального числа.
Решение
Решение
В своё время мне понравилась эта задача.
Сделаем подсчёт каждого значения. (на это указывает ограничение в условие ).
Число является квадратом, если каждое встречается чётное количество раз в . ().
Количество простых чисел в диапазоне всего . Значит где-то тут будут маски!!
Пронумеруем простые числа в диапазоне числа
Напишем по маскам.
- Состояние — количество способов выбрать из массива значения и собрать . Где — если простое -ое простое число встречается нечётное количество раз в . если чётное, в противном случае.
- начальное значение.
- Переход :
-- количество способов выбрать нечётное количество элементов из
-- аналогично чётное.
Количество способов выбрать чётное количество элементов из множества , равняется , для нечётных тоже самое.
В переходе если мы берём любое чётное количество раз, мы не изменим .
В переходе логично изменим степени простых, которые пересекаются с маской от числа на противоположные. 4. Ответ — . ( так как мы пустое множество по условию не считаем, вроде?, мне уже лень думать)
int P[71];
int primeOrder[71];
int get_mask(int x) {
if (x == P[x]) return (1 << primeOrder[x]);
int mask = 0;
while (x != 1) {
int pr = P[x];
int p = 0;
while (x % pr == 0) {
p++;
x /= pr;
}
if (p % 2 == 1) {
mask += (1 << primeOrder[pr]);
}
}
return mask;
}
void solve() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
cnt[x]++;
}
for (int i = 2; i <= 70; i++) {
if (!P[i]) {
for (int j = 2 * i; j <= 70; j += i) {
P[j] = i;
}
P[i] = i;
}
}
int cur = 0;
for (int i = 2; i <= 70; i++) {
if (P[i] == i) {
primeOrder[i] = cur++;
}
}
dp[0][0] = 1;
for (int i = 0; i < 70; i++) {
int CH = ch_comb(cnt[i + 1]);
int NCH = nch_comb(cnt[i + 1]);
int nxt_mask = get_mask(i + 1);
for (int cur_mask = 0; cur_mask < (1 << cur); cur_mask++) {
dp[i + 1][cur_mask ^ nxt_mask] =
(dp[i + 1][cur_mask ^ nxt_mask] + 1LL * dp[i][cur_mask] * NCH) % mod;
dp[i + 1][cur_mask] =
(dp[i + 1][cur_mask] + 1LL * dp[i][cur_mask] * CH) % mod;
}
}
cout << (dp[70][0] - 1 + mod) % mod;
}