1. 程式人生 > 其它 >CF1497E1 Square-free division (easy version)題解

CF1497E1 Square-free division (easy version)題解

根號居然能過就離譜。。。不愧是CF神機

題意

給你一個長度為\(n\)的序列,你需要把這個序列分成若干段,使得每一段滿足:從這一段中任意選擇兩個數,使得這兩個數的乘積不為完全平方數。最小化分的段數,問你最少分成多少段。

分析

發現完全平方數其實就是質因數分解之後每一個質因子的冪次都為偶數的數,那麼只要有一個質因子的冪次為奇數,這個數就不是完全平方數。所以對於一個數的一些冪次為奇數的因子,必須要有一個數,這個數的所有冪次為奇數的因子與他完全一致,這兩個數才能湊成完全平方數。所以我們就有一個暴力的做法:我們從左往右處理每一個數字,每遇到一個數字我們就把這個數字質因數分解。然後我們把它的冪次為偶數的質因子忽略,只考慮它冪次為奇數的質因子,如果它之前存在一個數,那個數的奇數次質因子集合與它完全相同,那麼這兩個數顯然不能放在同一段裡,也就是需要貪心的分成兩段,如果沒有,那麼就把這個數加入之前的那一段然後把這個數的質因子記錄下來。
考慮怎麼實現,發現需要一個可以支援插入和查詢一個集合是否存在,可以用雜湊,但是我們發現,考慮所有的質數,如果他們不同,那麼他們的乘積也肯定不同,所以我們只需要用乘積來代表一個質因數的集合然後用map維護即可。
總複雜度為\(O(n\sqrt{INT\_MAX)}\)

,但是能過(

程式碼


/* Creat on Xishui's iPad 
    Author: Xishui
    date: 21/10/21
    Language: C++
*/

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,k;
int devide(int x){
    int ret=1;
    if(x==1)
        return 1;
    for(int i=2;i*i<=x;i++){
        int cnt=0;
        while(x%i==0){
            x/=i;
            cnt++;
        }
        if(cnt%2)
            ret*=i;
    }
    return ret*x;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        int ans=0;
        map<int,int>ret;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);    
            int res=devide(x);
            if(ret[res]){
                ans++;
                ret.clear();
            }
            ret[res]=1;
        }
        printf("%d\n",ans+1);
    }
    return 0;
}