zoukankan      html  css  js  c++  java
  • [E. Ehab's REAL Number Theory Problem](https://codeforces.com/contest/1325/problem/E) 数论+图论 求最小环

    E. Ehab's REAL Number Theory Problem 数论+图论 求最小环

    题目大意:

    给你一个n大小的数列,数列里的每一个元素满足以下要求:

    • 数据范围是:(1<=a_i<=10^6)
    • (a_i) 最多只有7个因数

    题目要求在这个数列找到一个最短的子数列,子数列的所有的数相乘是一个完全平方数。

    题解:

    • 这个题对于 (x^{3}) 应该等价于 (x) ,其实就是可以除去 (a_i)中的所有的平方项,显而易见,这个并不影响答案。
    • 因为 (a_i) 最多只有7个因素,由素数唯一分解定理可得每一个元素最多 2 个质因子。
    • 所以删去平方项之后,每一个元素就会要么是两个素因子相乘,要么就是一个素因子。
    • 此时,我们把每一个素因子当初一个节点,如果一个素数是由哪两个素因子相乘,那就可以连一条边,如果只有一个元素,把1也当作素因子看做一个节点。
    • 这样就变成一个图论问题,求无向无权图的最小环。
    • 直接暴力每一个点都是起点,因为每一个元素至少有一个素因子是小于1000,所以这个时候我们遍历从1到1000每一个值都是起点,就可以遍历到每一个元素,在这里求最小环即可。
    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int maxn=1e6+10;
    struct node{
        int v,nxt;
        node(int v=0,int nxt=0):v(v),nxt(nxt){}
    }e[maxn];
    int head[maxn],cnt,isp[maxn],v[maxn],m,f,ans,a[maxn],num;
    void init(){//只需要求1000以内的素数即可
        cnt=f=num=0,ans=inf;
        memset(head,-1,sizeof(head));
        for(int i=2;i<1000;i++){
            if(!v[i]){
                isp[m++]=i;
                v[i]=i;
            }
            for(int j=0;j<m;j++){
                if(v[i]<isp[j]||i*isp[j]>=1000) break;
                v[i*isp[j]]=isp[j];
            }
        }
    }
    void add(int u,int v){
        a[++num]=u,a[++num]=v;//求出所有的素数
        e[cnt]=node(v,head[u]);
        head[u]=cnt++;
        e[cnt]=node(u,head[v]);
        head[v]=cnt++;
    }
    void judge(int x){
        int div[5],tot=0;
        for(int i=0;i<m;i++){
            if(x%isp[i]==0){
                while(x%(isp[i]*isp[i])==0) x/=isp[i]*isp[i];
                if(x%isp[i]==0) div[++tot]=isp[i],x/=isp[i];
            }
        }
        if(tot==0&&x==1) {f=1;return ;}
        if(x>1) div[++tot]=x;
        if(tot==1) add(1,div[1]);
        else add(div[1],div[2]);
    }
    int d[maxn];
    typedef pair<int,int>pii;
    void bfs(int s){
        for(int i=1;i<=num;i++) d[a[i]]=inf;//只需要初始化在图中的素数
        d[s]=0;queue<pii>que;
        que.push(pii(s,0));
        while(!que.empty()){
            pii u=que.front();que.pop();
            for(int i=head[u.first];~i;i=e[i].nxt){
                int v=e[i].v;
                if(v==u.second) continue;
                if(d[v]==inf){
                    d[v]=d[u.first]+1;
                    que.push(pii(v,u.first));
                }
                else ans=min(ans,d[u.first]+d[v]+1);
            }
        }
    }
    int main(){
        init();int n;
        scanf("%d",&n);
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);judge(x);
        }
        sort(a+1,a+1+num);
        num=unique(a+1,a+1+num)-a-1;
        if(f) {printf("1
    ");return 0;}
        bfs(1);
        for(int i=0;i<m;i++) bfs(isp[i]);
        if(ans==inf) printf("-1
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    
    
    
  • 相关阅读:
    常忘知识点一:嵌套属性
    button按钮的状态为disabled禁用状态,click事件无法触发,但是为什么touchstart下却依然可以触发
    shell
    sql help cs
    再次写给我们这些浮躁的程序员
    C# winform进度条 (异步)
    关于C# WinForm中进度条的实现方法
    Oracle 多行记录合并/连接/聚合字符串的几种方法
    PL/SQL编码规范的一些建议
    PL/SQL 日期时间类型函数及运算
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/12558110.html
Copyright © 2011-2022 走看看