Editorial for Coprime Subsequences
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Solución 1
Resolvamos un problema más general: Dados una secuencia de enteros positivos y un entero positivo , calcular cuántas subsecuencias hay tal que el gcd de todos sus elementos sea , (llamemos a esta cantidad ). La respuesta al problema original sería cuando , (es decir, .
Observaciones:
- Si el gcd de una subsecuencia es , entonces todos los elementos de la subsecuencia deben ser múltiplos de .
- El conjunto de elementos múltiplos de tiene como subsecuencias a:
- Las subsecuencias cuyo gcd es .
- Las subsecuencias cuyo gcd es .
- Las subsecuencias cuyo gcd es .
- Las subsecuencias cuyo gcd es .
- ...
Por tanto, [Cantidad de subsecuencias consistentes solamente de múltiplos de ].
Obviamente, la cantidad de subsecuencias consistentes solamente de múltiplos de es igual a .
Por tanto, si es el número de múltiplos de en el arreglo, entonces , lo que quiere decir que:
No vamos iterar por todos los múltiplos de hasta el infinito. Solo tenemos que iterar por los múltiplos de menores o iguales que el máximo valor del arreglo. Llamemos al máximo valor del arreglo.
Entonces, iteramos por de manera decreciente desde hasta ; y para cada , usamos la recurrencia de arriba para computar en tiempo .
La complejidad temporal para calcular sería . Notemos que en el código mostrado abajo calculamos los divisores de iterando hasta , por lo cual esa parte toma en total tiempo .
Para otras formas de calcular cnt[] véase este artículo.
Código de ejemplo:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = (ll)1e9 + 7;
const int maxn = (int)2e5 + 5;
ll add(ll x, ll y){ return (x + y)%mod; }
ll rest(ll x, ll y){ return (x + mod - y)%mod; }
ll f[maxn]; // f[x]: cantidad de subsecuencias cuyo gcd es x
int cnt[maxn]; // cnt[x]: cantidad de múltiplos de x
ll ptwo[maxn]; // pwto[x]: 2 elevado a la x
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; i++){
ll x;
cin >> x;
for(int j = 1; j * j <= x; j++){
if(x % j == 0){
cnt[j]++;
if(j * j != x)
cnt[x/j]++;
}
}
}
ptwo[0] = 1;
for(int i = 1; i <= n; i++)
ptwo[i] = add(ptwo[i-1], ptwo[i-1]);
for(int g = maxn - 1; g >= 1; g--){
f[g] = rest(ptwo[cnt[g]], 1); //realmente aquí no es necesario usar rest(), ya que ninguna potencia de 2 es múltiplo de 1e9 + 7
for(int t = 2*g; t < maxn; t+=g)
f[g] = rest(f[g], f[t]);
}
cout << f[1];
return 0;
}
Solución 2
En esta solución usaremos principio de inclusión exclusión. Definamos como el mayor valor del arreglo. Sean la secuencia de todos los primos menores o iguales que , (o sea, ). Sea el conjunto de subsecuencias de tales que todos sus números son múltiplos de , por ejemplo: sería el conjunto de todas las subsecuencias que consisten solamente de números pares.
Entonces, lo que queremos hallar es la cardinalidad (cantidad de elementos) del complemento de la unión de los . Es decir, de todas las posibles subscuencias, quitaremos las que pertenecen a al menos uno de los conjuntos , y la cantidad de subsecuencias restantes es la respuesta. La solución sería:
Para calcular , según el principio de inclusión exclusión, iteramos por todos los subconjuntos de y añadimos (en caso de que el subconjunto actual tenga tamaño impar) o restamos (en caso de que tenga tamaño par) a la solución el tamaño de la intersección de los del subconjunto actual. Digamos que el subconjunto actual es , entonces lo que debemos añadir a la respuesta es la cantidad de subsecuencias que consisten solamente de múltiplos de , que es .
Obviamente, no podemos hacer esto explícitamente ya que hay demasiados primos. Notemos que hay una biyección entre cada subconjunto y los productos . Entonces, la respuesta es:
Aquí, es la función de Moebius, que retorna 0 si no es libre de cuadrados (si tiene un primo con exponente mayor que 1 en su factorización), -1 si tiene una cantidad impar de factores primos, y 1 si tiene una cantidad par de factores primos. Para calcular la función de Moebius, podemos usar el hecho de que es una función multiplicativa, y computar los primos con una criba.
La complejidad de esta solución depende de la criba y de qué tan rápido computamos (referirse a este artículo). Se puede lograr complejidad .
Código de ejemplo:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (int)2e5 + 5;
const ll mod = (int)1e9 + 7; // 998244353
ll add(ll x, ll y){
return (x + y)%mod;
}
ll rest(ll x, ll y){
return add(x, mod - y);
}
ll mul(ll x, ll y){
return x * y % mod;
}
int cnt[maxn], p[maxn], mu[maxn];
ll ptwo[maxn];
void sieve(){
for(int i = 2; i < maxn; i+=2) p[i] = 2;
for(int i = 3; i < maxn; i+=2) p[i] = i;
for(int i = 3; i * i < maxn; i+=2)
if(p[i] == i)
for(int j = i*i; j < maxn; j+=2*i)
p[j] = i;
mu[1] = 1;
for(int i = 2; i < maxn; i++){
int j = i, k = 0;
while(j % p[i] == 0)
j /= p[i], k++;
if(j == 1)
mu[i] = rest(k == 0, k == 1);
else
mu[i] = mul(mu[j], mu[i/j]);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int n;
cin >> n;
ptwo[0] = 1;
for(int i = 1; i <= n; i++){
ll x; cin >> x;
for(int j = 1; j * j <= x; j++){
if(x % j == 0){
cnt[j]++;
if(j * j != x)
cnt[x/j]++;
}
}
ptwo[i] = mul(ptwo[i-1], 2);
}
sieve();
ll ans = 0;
for(int t = 1; t < maxn; t++)
ans = add(ans, mul(mu[t], rest(ptwo[cnt[t]], 1)));
cout << ans;
return 0;
}
Comments