CF1497E1 Square-free division (easy version)

Square-free division (easy version)

This is the easy version of the problem. The only difference is that in this version k=0.

 

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 k such operations before the division: choose a number in the array and change its value to any positive integer. But in this version k=0, so it is not important.

 

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 (1≤t≤1000)  — the number of test cases.

 

The first line of each test case contains two integers n, k (1≤n≤2⋅105, k=0).

 

The second line of each test case contains n integers a1,a2,…,an (1≤ai≤107).

 

It's guaranteed that the sum of n over all test cases does not exceed 2⋅105.

 

Output

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

解题思路

学习了一波官方题解的思路
大致思路为,对于同一分段中的两个数,他们的因子中任意一对因子对的因子数奇偶性不同(否则就可以将所有的因子分为相等的两部分,两个数的乘积即为一部分的平方)。所以我们只要统计每个数的因子的奇偶的情况,然后再贪心地做判断就可以了。
 
还是像上次一样给出附有我的思路的代码吧
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 using ll = long long;
 4 vector<int> primes;
 5 const int MAXN = 1e7;
 6 int mind[MAXN + 10];
 7 void pre()                                    //统计对于范围内的每一个数,它最小的因子是多少
 8 {
 9     for (int i = 2; i < MAXN; i++)
10     {
11         if (mind[i] == 0)                //如果一个数没有被统计过,说明他是质数,其自身为其最小因子
12         {
13             primes.emplace_back(i);
14             mind[i] = i;
15         }
16         for (auto& x : primes)            //将这个数的2,3,5···倍的数的最小因子标记为2,3,5···实现函数目标
17         {
18             if (x > mind[i] || x * i > MAXN)    //范围
19                 break;
20             mind[x * i] = x;
21         }
22     }
23 }
24 void solve()
25 {
26     int n, k;
27     cin >> n >> k;
28     vector<int> a(n, 1);
29     for (int i = 0; i < n; i++)
30     {
31         int x;
32         cin >> x;
33         int cnt = 0;                    //统计当前因子的树木
34         int last = 0;                   //统计当前因子是多少
35         while (x > 1)                   //循环找出输入x的每一个因子
36         {
37             int p = mind[x];            //当前的最小因子
38             if (last == p)              //如果当前数x的最小因子不变,将cnt++
39                 cnt++;
40             else                        //如果因子变了,进入else进行统计
41             {
42                 if (cnt % 2 == 1)       //如果该因子的数量为奇数,将a[i]*last,将last统计到a[i]中
43                     a[i] *= last;
44                 last = p;               //更新为新因子
45                 cnt = 1;                //重置
46             }
47             x /= p;                     //这个因子统计过了,将x除以p
48         }
49         if (cnt % 2 == 1)               //因为最后一次循环时不会进入else统计,所以要在循坏外统计一次
50             a[i] *= last;
51     }
52     //输出部分
53     int pos = 0;                        //上一次分段的位置
54     int    ans = 1;                     //结果
55     map<int, int> last;                 //这个数之前的分段
56     for (int i = 0; i < n; i++)
57     {
58         if (last.find(a[i]) != last.end() && last[a[i]] >= pos)        //找到了一个多余因子相同,且在上一段中的数,说明这两个数相乘后为完全平方数,进行分段操作
59         {
60             ans++;                      //++
61             pos = i;                    //更新分段位置
62         }
63         last[a[i]] = i;                //将这个数加入总数组
64     }
65     cout << ans << "\n";
66 }
67 int main()
68 {
69     ios::sync_with_stdio(false);
70     cin.tie(0);
71 
72     pre();
73     int t;
74     cin >> t;
75     while (t--)
76     {
77         solve();
78     }
79     return 0;
80 }

 

 

这道题似乎还有一种用set的解法,且等我去学习一波

posted @ 2021-03-19 17:20  icey_z  阅读(131)  评论(0)    收藏  举报