数论杂记——约数个数定理

Posted Y-KnightQin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论杂记——约数个数定理相关的知识,希望对你有一定的参考价值。

 

 

 例题:codeforces 1325E

1. 题目解释每个数的因数个数不超过7个,说明了每个数最多只有2个质因数,因为如果有3个质因数的话,那么 f(n)=(1+1)^3=8>7不成立了。

2. 求出的答案要使得乘积为完全平方,因此答案的质因数个数必须为偶数个,即a1、a2……要为偶数。

3. 答案的质因数个数必须为偶数个,等价于选最少的数,使乘积包含的质因子幂次都为 2。如果一个数本身的质因数个数都为偶数,则直接输出1即可,如果没有这样的数,我们可以考虑尝试把每个数的质因数凑在一起,使得质因数个数都为偶数,这样也可以求出答案,如果连凑都凑不出来,则输出-1.

4. 考虑尝试把每个数凑起来的方法比较巧妙,我们建立一个无向图,每个点代表了一个质因子,如果某个数有两个独立的质因子,也就是说只有这两个质因数凑不了偶数,那么我们就把这两个数连一条边,说明这两个数的个数都为1(入度为1),这有什么用呢?考虑无向图的性质,如果每个点的入度为 2,所以边对应的数的乘积每个质因子幂次都为 2,这就要让我们找出无向图中所存在的最小环。

这题数论与图论的结合十分巧妙,所以我们要有充足的前备知识才能做得出这道题目。

#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
inline int read(){int s=0,w=1;char ch=getchar();
while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')w=-1;ch=getchar();}
while(ch>=\'0\'&&ch<=\'9\') s=s*10+ch-\'0\',ch=getchar();
return s*w;}
const int maxn = 1000005;
const int INF = 0x3f3f3f3f;
int ip[maxn],i,n,p[maxn],cnt,dis[maxn],a[maxn],ans;
bool vis[maxn];
vector <int> G[maxn];
void get_prime()
{
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    p[1]=1;
    ip[1]=1;
    cnt=1;
    for (int i=2;i<=maxn;i++)
    {
        if(!vis[i]) 
        {
            cnt++;
            p[cnt]=i;
            ip[i]=cnt;
        }
        for (int j=1;j<=cnt && i*p[j]<=maxn;j++)
        {
            vis[i*p[j]]=1;
        }
    }
}
void add(int x,int y)
{
    G[x].push_back(y);//to[point++]=y;
    G[y].push_back(x);//to[point++]=x;
}
void DIV(int x)
{
    int div[5],num=0;
    for (int i=2;i<=cnt && p[i]*p[i]<=x;i++)
    {
        if (x % p[i]==0)
        {
            while (x%(p[i]*p[i])==0) x/=p[i]*p[i];
            if (x%p[i]==0) 
            {
                num++;
                div[num]=i;
                x/=p[i];
            }
        }
    }
    if (x>1) 
    {
        num++;
        div[num]=ip[x];
    }
    if (num==0) puts("1"),exit(0);
    else if(num==1) add(1,div[1]);
    else add(div[1],div[2]);
}
int bfs(int x)
{
    queue<pair<int,int> >q;
    q.push(mp(x,0));
    memset(dis,0,sizeof(dis));
    dis[x]=1;
    while (!q.empty())
    {
        int u=q.front().first;
        for (auto v:G[u])
        {
            if (v==q.front().second) continue;
            if (dis[v]) return dis[u]+dis[v]-1;
            q.push(mp(v,u));
            dis[v]=dis[u]+1;
        }
        q.pop();
    }
    return INF;
}
int main()
{
    get_prime();
    n=read();
//    for (i=1;i<=100;i++) cout<<p[i]<<endl;
    for (i=1;i<=n;i++)
    {
        a[i]=read();
        DIV(a[i]);
    }
    ans=INF;
    for (i=1;i<=1000;i++) 
    {
        ans=min(ans,bfs(i));
    }
    if (ans==INF) cout<<-1<<endl;
        else cout<<ans<<endl;
    return 0;
}
View Code

 

7

以上是关于数论杂记——约数个数定理的主要内容,如果未能解决你的问题,请参考以下文章

(寒假练习 AcWing 870)约数个数(数论)

简单数论——约数

hdu 1215 求约数和 唯一分解定理的基本运用

LeetCode数论题目总结

JZYZOJ1379天才的约数和 数论 约数和

数论考试题(b) 求约数的约数的最大个数