数论杂记——约数个数定理
例题: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; }
7