Título
Codeforces 1497E2 División sin cuadrados (versión dura)
respuesta
De acuerdo con el teorema básico de la aritmética, sea a = ∑ pieia = \ sum p_i ^ {e_i}a=∑pagImiyo. Si el producto de dos números es un número cuadrado perfecto, entonces el término exponente ei e_i de los dos númerosmiyoEs el factor primo impar pi p_ipagyoSi el conjunto es el mismo, entonces se puede usar el producto de dichos factores primos ∏ pi \ prod p_i∏pagyoLa única representación. Tamiz lineal O (N) O (N)O ( N ) preprocesos[1, A] [1, A][ 1 ,A ] es el factor primo más pequeño, luegoO (N log A) O (N \ log A)O ( Nlo gA ) Resuelve la representación única de cada elemento.
Luego, las condiciones de restricción en el mismo párrafo se transforman en el único significado de que no hay dos números iguales . Enumere el punto final izquierdo del último párrafo, dp [i] [j] dp [i] [j]d p [ i ] [ j ] representa los subelementos[1, i] [1, i][ 1 ,i ] no cambia más quejjEl número mínimo de segmentos que se pueden dividir entre j números, la complejidad de tiempo total esO (N 2 K 2) O (N ^ 2K ^ 2)O ( N2 K2 )Evidentemente, es difícil hacer el trabajo. ObservarjjCuando j es el mismo,dp [i] [j] dp [i] [j]d p [ i ] [ j ]随着iii aumenta sin disminuir monótonamente, entonces si podemos resolver paraiii es el punto final derecho y no cambia más quejjEl extremo más a la izquierdalb [i] [j] lb [i] [j] de los j dígitos que satisfacen el intervalo condicionall b [ i ] [ j ] , luegoDP DPD P la complejidad del tiempo total se reduce aO (NK 2) O (NK ^ 2)O ( N K2 )。
dp [i] [j] = min 0 ≤ k ≤ jdp [lb [i] [k] - 1] [j - k] + 1 dp [i] [j] = \ min \ limits_ {0 \ leq k \ leq j} dp [lb [i] [k] -1] [jk] +1d p [ i ] [ j ]=0 ≤ k ≤ jyod p [ l b [ i ] [ k ]-1 ] [ j-k ]+1 observadojjCuando j es el mismo, cuando el límite derecho del intervalo que satisface la condición se mueve hacia la izquierda, el límite izquierdo no se moverá hacia la derecha, puede usar la reglaO (KN) O (KN)O ( K N )求解lb [i] [j] lb [i] [j]l b [ i ] [ j ]。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005, maxk = 22, maxa = 10000005, inf = 0x3f3f3f3f;
int T, N, K, A[maxn], id[maxn];
int np, prime[maxa], minp[maxa];
int cnt[maxa], lb[maxn][maxk], dp[maxn][maxk];
void sieve()
{
for (int i = 2; i < maxa; ++i)
{
if (!minp[i])
minp[i] = i, prime[++np] = i;
for (int j = 1; j <= np && i * prime[j] < maxa; ++j)
{
minp[i * prime[j]] = prime[j];
if (minp[i] == prime[j])
break;
}
}
}
int main()
{
sieve();
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &N, &K);
for (int i = 1; i <= N; ++i)
scanf("%d", A + i);
for (int i = 1; i <= N; ++i)
{
int a = A[i], x = 1, cnt = 0, lst = 0;
while (a != 1)
{
int p = minp[a];
if (p == lst)
++cnt;
else
{
if (cnt & 1)
x *= lst;
cnt = 1, lst = p;
}
a /= p;
}
if (cnt & 1)
x *= lst;
id[i] = x;
}
for (int j = 0; j <= K; ++j)
{
int l = N + 1, sum = 0;
for (int i = N; i; --i)
{
while (l - 1 >= 1 && sum + (cnt[id[l - 1]] > 0) <= j)
--l, sum += cnt[id[l]] > 0, ++cnt[id[l]];
lb[i][j] = l;
sum -= --cnt[id[i]] > 0;
}
}
for (int i = 1; i <= N; ++i)
for (int j = 0; j <= K; ++j)
dp[i][j] = inf;
for (int j = 0; j <= K; ++j)
dp[0][j] = 0;
for (int i = 1; i <= N; ++i)
for (int j = 0; j <= K; ++j)
for (int k = 0; k <= j; ++k)
dp[i][j] = min(dp[i][j], dp[lb[i][k] - 1][j - k] + 1);
printf("%d\n", dp[N][K]);
}
return 0;
}