Codeforces 1497E2 linear sieve + ruler picking method + DP

Title

Codeforces 1497E2 Square-free division (hard version)

answer

According to the basic theorem of arithmetic, let a = ∑ pieia=\sum p_i^{e_i}a=piei. If the product of two numbers is a perfect square number, then the exponent term ei e_i of the two numberseiIs odd prime factor pi p_ipiIf the set is the same, then the product of such prime factors can be used ∏ pi \prod p_ipiThe only representation. Linear sieve O (N) O (N)O ( N ) preprocesses[1, A] [1, A][1,The smallest prime factor of A ] can beO (N log ⁡ A) O(N\log A)O ( NlogA ) Solve for the unique representation of each element.

Then the restriction conditions in the same paragraph are transformed into the unique meaning that there are no two numbers . Enumerate the left end point of the last paragraph, dp [i] [j] dp[i][j]d p [ i ] [ j ] represents the sub-elements[1, i] [1,i][1,i ] does not change more thanjjThe minimum number of segments that can be divided by j numbers, the total time complexity isO (N 2 K 2) O(N^2K^2)O ( N2 K2 )Obviously it is difficult to do the job. ObservejjWhen j is the same,dp [i] [j] dp[i][j]dp[i][j] 随着 i i i increases without decreasing monotonously, then if we can solve foriii is the right end point and does not change more thanjjThe leftmost endpointlb [i] [j] lb[i][j] of the j digits satisfying the conditional intervall b [ i ] [ j ] , thenDP DPD P total time complexity is reduced toO (NK 2) O(NK^2)O ( N K2)
d p [ i ] [ j ] = min ⁡ 0 ≤ k ≤ j d p [ l b [ i ] [ k ] − 1 ] [ j − k ] + 1 dp[i][j]=\min\limits_{0\leq k\leq j}dp[lb[i][k]-1][j-k]+1 dp[i][j]=0kjmedp[lb[i][k]1][jk]+1 observedjjWhen j is the same, as the right boundary of the interval that satisfies the condition moves to the left, the left boundary will not move to the right, you can use the rulerO (KN) O(KN)O(KN) 求解 l b [ i ] [ j ] lb[i][j] lb[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;
}

Guess you like

Origin blog.csdn.net/neweryyy/article/details/115266153