CF1497 E2. Squarefree division (hard version)

Problem - E2 - Codeforces

题意:

有n个正整数,你至多可以把其中k个修改为任意的正整数

你需要把这n个数划分为若干个连续的段,满足每一段的任意两个数的乘积都不是完全平方数

问最少划分为多少段

任意两个数的乘积都不是完全平方数

等价于

把区间内的数质因子分解,每个质因子的指数对2取模,任意两个数的结果都是不同的。

因为可以修改为任意的正整数,所以相当于每个区间内质因子分解指数对2取模的结果至多有k个位置可以与区间内前面的数相同

设dp[i][j]表示前i个数至多修改了j个位置的最少划分段数

枚举最后一段修改了p个位置,假设这最后一段是区间[x,i],那么dp[i][j]可以用dp[x-1][j-p]+1更新

就剩下x怎么求了

预处理le[i][j]表示区间[L,i]至多修改j个数,满足要求的最小的L

这个可以先枚举j,对于每个j用双指针的方法解决

#include<bits/stdc++.h>

using namespace std;

#define N 200004

int dp[N][21],le[N][21]; 
int cnt[10000001];
int a[N];

int main()
{
    int T,n,k,x,y,l;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i) 
        {
            scanf("%d",&a[i]);
             x=1;
            for(int j=2;j*j<=a[i];++j)
                 if(!(a[i]%j))
                {
                    y=0;
                    while(!(a[i]%j))
                    {
                        ++y;
                        a[i]/=j;
                    }
                    if(y&1) x*=j;
                 }
             a[i]*=x;
        }
        for(int i=0;i<=k;++i)
        {
            x=0;
            l=1;
            for(int r=1;r<=n;++r)
             {
                 cnt[a[r]]++;
                 if(cnt[a[r]]!=1) ++x;
                while(x>i)
                {
                    cnt[a[l]]--;
                    if(cnt[a[l]]) --x;
                    ++l; 
                }
                le[r][i]=l;
             }
            while(l<=n) cnt[a[l++]]--;
        }
        for(int i=1;i<=n;++i)
            for(int j=0;j<=k;++j)
                dp[i][j]=n;
        for(int i=1;i<=n;++i)
            for(int j=0;j<=k;++j)
                for(int p=0;p<=j;++p)
                    dp[i][j]=min(dp[i][j],dp[le[i][p]-1][j-p]+1);
        printf("%d\n",dp[n][k]);
    }
}
作者:xxy
本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/15546141.html