Codeforces Round #708 (Div. 2) E2. Square-free division (hard version)

            E2. Square-free division (hard version)

This is the hard version of the problem. The only difference is that in this version 0k20.

There is an array a1,a2,,an of n positive integers. You should divide it into a minimal number of continuous segments, such that in each segment there are no two numbers (on different positions), whose product is a perfect square.

Moreover, it is allowed to do at most kk such operations before the division: choose a number in the array and change its value to any positive integer.

What is the minimum number of continuous segments you should use if you will make changes optimally?

Input

The first line contains a single integer t(1t1000)  — the number of test cases.

The first line of each test case contains two integers nn, kk (1n21050k20).

The second line of each test case contains nn integers a1,a2,,an (1ai107).

It's guaranteed that the sum of nn over all test cases does not exceed 2105.

Output

For each test case print a single integer  — the answer to the problem.

Example
input
Copy
3
5 2
18 6 2 4 1
11 4
6 2 2 8 9 1 3 6 3 9 7
1 0
1
output
Copy
1
2
1
Note

In the first test case it is possible to change the array this way: [3,6,2,4,5] (changed elements are underlined). After that the array does not need to be divided, so the answer is 11.

In the second test case it is possible to change the array this way: [6,2,3,8,9,5,3,6,10–––,11–––,7]. After that such division is optimal:

  • [6,2,3]
  • [8,9,5,3,6,10,11,7]

题目描述:给n个数,问你最少分成几份,使每份中任意两个数的积不是完全平方数。可以把某个数变化成任意数,共k次。

思路:考虑把每个数分解质因数,两个数相乘就是对应质因数的指数相加,而一个数要是完全平方数则他的质因数指数都是偶数,所以只要两个数对应质因数指数相加存在奇数,他们相乘就不会是完全平方数。所以可以把每个数分解质因数后,指数都%2,这样处理后,要组成完全平方数就肯定要两个相等的数。

这样题目就转换成每份不能有相同的数,如果k=0很简单,直接贪心判重就好。

当k>0的时候,就得用dp了。先处理出left[i][j]数组,表示以i结尾,向前去贪心,可以变化不超过j个数的最小下标L,使得L~i区间没有相同的数。用双指针来得到该数组。

dp[i][j]表示前i个数,变化不超过j次的最小划分,就是题目所求。

就有dp方程:           dp[i][j]=min(dp[ lef[i][p]-1 ][ j-p ]+1,dp[i][j],dp[i][j-1]);    i:1~n,  j:0~k,  p:0~j  

代码:

#include<bits/stdc++.h>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define sf(x) scanf("%lf",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define range(a,x,y) a+x,a+y+x
#define dbug printf("bbbk\n")
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll,ll> P;
const int N=2e5+99;
const int MN=1e7+9;
const ll mod=1e9+7;
const int INF=1e9+7;
int a[N],prm[MN],sz,cnt[MN];
bool isp[MN];
void pre()
{
    ms(isp,1);isp[1]=0;
    fu(i,2,MN-1)
    {
        if(isp[i]) prm[++sz]=i;
        for(int j=1;j<=sz&&i*prm[j]<MN;j++)
        {
            isp[i*prm[j]]=0;
            if(i%prm[j]==0) break;
        }
    }
}
int change(int x)
{
    if(isp[x]) return x;
    int cnt=0,ans=0;
    for(int j=1;j<=sz&&x>1;j++)
    {
        int i=prm[j];
        if(x%i==0) 
        {
            cnt=0;
            while(x%i==0) x/=i,cnt++;
            if(cnt&1) ans+=i;
            if(isp[x]) return ans+x;
        }
    }
    return ans;
}
ll lef[N][30];
int main() 
{
    pre();
    int t;cin>>t;
    while(t--)
    {
        int n,k;sd(n);sd(k);
        int maxa=0;
        fu(i,1,n)
        {
            sd(a[i]);
            a[i]=change(a[i]),maxa=max(maxa,a[i]);
        }
        fu(j,0,k)
        {
            int l=n+1,del=0;//del表示要删除的有多少个
            fd(i,n,1)
            {
                while(l-1>=1&&del+(cnt[a[l-1]]>0)<=j) 
                {
                    l--;
                    del+=(cnt[a[l]]>0);
                    cnt[a[l]]++;
                }
                lef[i][j]=l;
                if(cnt[a[i]]>1) del--;
                cnt[a[i]]--;
            }
        }
        vector< vector<int> > dp(n+1,vector<int>(k+1,INF));
        for(auto &ss:dp[0]) ss=0;
        fu(i,1,n)
        {
            fu(j,0,k)
            {
                if(j>0) dp[i][j]=dp[i][j-1];
                fu(p,0,j)
                {
                    dp[i][j]=min(dp[lef[i][p]-1][j-p]+1,dp[i][j]);
                }
            }
        }
        int ans=INF;
        for(auto &ss:dp[n]) ans=min(ans,ss);
        printf("%d\n",ans);
    }
    return 0;
}

 

posted on 2021-03-30 19:01  Aminers  阅读(98)  评论(0编辑  收藏  举报

导航