zoukankan      html  css  js  c++  java
  • 题解 洛谷 P3532 【[POI2012]ODL-Distance】

    (cnt(x))(x) 质因数分解后质因数的指数和,即将 (x) 不断除其一个约数来使其变为 (1) 所需的次数,其可以通过线性筛来预处理。

    不难发现:

    [large d(a_i,a_j)=cnt(a_i)+cnt(a_j)-2cnt(gcd(a_i,a_j)) ]

    考虑对于每个 (a_i),可以枚举其约数,即枚举与另一个数 (a_j)(gcd)。这样的话,(cnt(a_i))(cnt(gcd(a_i,a_j))) 就都确定下来了。要使 (d(a_i,a_j)) 最小,只需 (cnt(a_j)) 最小,于是可以处理出每个数的所有倍数中 (cnt) 最小的数,且该数在序列 ({ a_i }) 中。因为要求 (i ot = j),因此还需处理出次小值。

    然后就可以统计每个约数的最优贡献了,这样枚举到的约数不一定恰好为 (gcd(a_i,a_j)),但当枚举到 (gcd(a_i,a_j)) 一定会更优,所以最终的答案一定为 (gcd(a_i,a_j))

    #include<bits/stdc++.h>
    #define maxn 1000010
    #define all 1000000
    #define inf 1000000000
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,tot,ans,val;
    int a[maxn],p[maxn],cnt[maxn],mn1[maxn],mn2[maxn];
    bool tag[maxn];
    void init()
    {
        for(int i=2;i<=all;++i)
        {
            if(!tag[i]) p[++tot]=i,cnt[i]=1;
            for(int j=1;j<=tot;++j)
            {
                int k=i*p[j];
                if(k>all) break;
                tag[k]=true,cnt[k]=cnt[i]+1;
                if(i%p[j]==0) break;
            }
        }
    }
    void update(int d,int x)
    {
        if(cnt[a[x]]<cnt[a[mn1[d]]]) mn2[d]=mn1[d],mn1[d]=x;
        else if(cnt[a[x]]<cnt[a[mn2[d]]]&&x!=mn1[d]) mn2[d]=x;
    }
    void work(int d,int x)
    {
        int y=mn1[d]==x?mn2[d]:mn1[d],v=cnt[a[x]]+cnt[a[y]]-2*cnt[d];
        if(v<val||(v==val&&y<ans)) val=v,ans=y;
    }
    int main()
    {
        init(),read(n),cnt[0]=inf;
        for(int i=1;i<=n;++i) read(a[i]);
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j*j<=a[i];++j)
            {
                if(a[i]%j) continue;
                update(j,i),update(a[i]/j,i);
            }
        }
        for(int i=1;i<=n;++i)
        {
            val=inf;
            for(int j=1;j*j<=a[i];++j)
            {
                if(a[i]%j) continue;
                work(j,i),work(a[i]/j,i);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    c#委托 事件 lamda 简写
    c#委托 事件 lamda 简写
    SQL Server 存储过程返回结果集的几种方式
    SQL Server 存储过程返回结果集的几种方式
    C# WinForm 慎用 override CreateParams 来重载窗体的一些特性
    C# WinForm 慎用 override CreateParams 来重载窗体的一些特性
    sqlserver临时表的生命周期到底有多长
    基础练习 回文数
    基础练习 回文数
    信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言—— 1123:图像相似度
  • 原文地址:https://www.cnblogs.com/lhm-/p/13627630.html
Copyright © 2011-2022 走看看