cf 628 E. Ehab's REAL Number Theory Problem

题意

给定序列。
每个数不超过7个除数
求最小子序列使得乘积是完全平方数

题解

不超过7个除数,等价于最多两个质因数。
并且我们只关心质因数的奇次方。
所以我们除去所有的平方项,留下奇次方。
只要保证这个数的奇次方有两个,即是平方项了。

我们考虑,对于一个数建一条边,边上连两个质因数。
如果是质数,就连1和自己。

不是质数就不需要,因为对答案没有贡献
比如 10 = 2 5 10=2*5 ,如果连接1和10,那么要想有两个比如说 10 2 10*2 ,那么必然也有质因数 2 2 5 5 .
所以直接用 2 2 5 5 即可。

找最小环,这样对于上面的所有质因数都有两个数拥有,那么就是都是偶次方了。

找最小环用 b f s bfs ,枚举点去 b f s bfs ,因为你不知道哪个点在最小环上。
不过能保证的是,最小环上总有一个点小于 1 e 3 1e3 ,否则就存在有个数 > 1 e 6 >1e6 了 。
枚举 1 e 3 1e3 进行 b f s bfs

b f s bfs 判环就是记录距离,如果到下一个点的这条边没访问过,且下一个点已经被访问过,那么就是环。
对边标号进行 v i s vis 记录即可,直接令其等于当前源头,这样能避免清空的复杂度。

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn = 1e6+50;

typedef long long ll;

int cnt=0;
vector<pair<int,int> >G[maxn];
int vis[maxn],len[maxn],ans=0x3f3f3f3f;

void bfs(int i){
    queue<int>q;
    q.push(i);
    memset(len,0x3f,sizeof(len));
    len[i]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
//        cout<<u<<":"<<" ";
        for(auto it:G[u]){
            int v=it.first,id=it.second;
            if(vis[id]==i)continue;
//            cout<<v<<" ";
            vis[id]=i;
            if(len[v]!=0x3f3f3f3f)ans=min(ans,len[u]+len[v]+1);
            else len[v]=len[u]+1,q.push(v);
        }
//        puts("");
    }
}

int main(){
    int n,x;cin>>n;
    FOR(i,1,n){
        scanf("%d",&x);
        for(int j=2;j<=sqrt(x);j++){
            while(x%(j*j)==0)x/=j*j;
        }
        if(x==1){
            puts("1");
            return 0;
        }
        vector<int>tmp;
        for(int j=2;j<=sqrt(x);j++){
            if(x%j==0){
                tmp.push_back(j);
                while(x%j==0)x/=j;
            }
        }
        if(x!=1)tmp.push_back(x);
        if(tmp.size()==1){
            G[1].push_back(make_pair(x,++cnt));
            G[x].push_back(make_pair(1,cnt));
        }
        else{
            G[tmp[0]].push_back(make_pair(tmp[1],++cnt));
            G[tmp[1]].push_back(make_pair(tmp[0],cnt));
        }
    }
    FOR(i,1,sqrt(maxn-1))bfs(i);
    if(ans==0x3f3f3f3f)puts("-1");
    else cout<<ans<<endl;
}

其实这题我一开始也不会看的是题解,但是网上很多人用除数建边,我觉得常数有点大,用质因数的话就能少 7 7 倍的边。最后跑了 1300 m s 1300ms

在这里插入图片描述

发布了203 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/104964928