NKOI 3805 距离

P3805距离
时间限制 : - MS   空间限制 : 165536 KB 
评测说明 : 3000ms
问题描述

对于两个正整数a、b,这样定义函数d(a,b):每次操作可以选择一个质数p,将a变成a*p或a/p,

如果选择变成a/p就要保证p是a的约数,d(a,b)表示将a变成b所需的最少操作次数。
例如d(69,42)=3。

现在给出n个正整数A1,A2,...,An,对于每个i (1<=i<=n),求最小的j(1<=j<=n)使得i≠j且d(Ai,Aj)最小。

 

输入格式

第一行一个正整数n (2<=n<=100,000)。
第二行n个正整数A1,A2,...,An (Ai<=1,000,000)。

输出格式

输出n行,依次表示答案。

样例输入

6
1
2
3
4
5
6

样例输出

2
1
1
2
1
2


来源  poi 2012 distance













这道题我们先想一下怎么暴力做
如果要暴力,设g[i]为i的所有质因数的数量,我们首先推出d(a,b)=g[a]+g[b]-2*g[gcd(a,b)],然后枚举每一个a,b然后更新答案就可以了
这里的g[i]是很好求出的
但是考虑到n的数据,我们肯定不能直接暴力
枚举a[i],由于g[a[i]]相对不变,我们需要找到g[a[j]]-2*g[gcd(a[i],a[j])]的最小值
因此我们用f[x]表示因数为x的倍数a[j]使得g[a[j]]最小
由于要求i!=j因此我们维护一个最小值和次小值,所以f数组要开两维
#include
#include
using namespace std;
const int maxn=1e5+5,maxm=1e6+5,inf=1e9;
int n,a[maxn],f[maxm][2],g[maxm],maxx=0,prime[maxn],tot;
int ans,curid;
inline void _read(int &x){ 
    char t=getchar();bool sign=true; 
    while(t<'0'||t>'9') 
    {if(t=='-')sign=false;t=getchar();} 
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0'; 
    if(!sign)x=-x; 
}
void g_table(){//打印g数组
	int i,j;
	g[0]=inf;
	for(i=2;i<=maxx;i++){
		if(!g[i])prime[++tot]=i,g[i]=1;
		for(j=1;j<=tot&&i*prime[j]<=maxx;j++){
			g[i*prime[j]]=g[i]+1;
			if(!(i%prime[j]))break;
		}
	}
}
void update(int x,int k){更新f[][]数组
	if(g[a[x]]<=g[a[f[k][0]]])f[k][1]=f[k][0],f[k][0]=x;
	else if(g[a[x]]<=g[a[f[k][1]]])f[k][1]=x;
}
void ok(int i,int j){
	int k=j,x;
	if(f[k][0]!=i)x=f[k][0];
	else x=f[k][1];
	int temp=g[a[x]]-2*g[k];
	if(temp



提交

你可能感兴趣的:(数论)