[BZOJ2790][Poi2012]Distance
2790: [Poi2012]Distance
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 225 Solved: 115
[Submit][Status][Discuss]
Description
对于两个正整数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)最小。
Input
第一行一个正整数n (2<=n<=100,000)。第二行n个正整数A1,A2,...,An (Ai<=1,000,000)。
Output
输出n行,依次表示答案。
Sample Input
6
1
2
3
4
5
6
1
2
3
4
5
6
Sample Output
2
1
1
2
1
2
1
1
2
1
2
HINT
Source
很容易推出来 $d(x,y)=g(x)+g(y)-2*g(\gcd(x,y))$ 其中g(x)表示x是几个质数的乘积
$g$函数只需要一个线性筛就能求出来,对于$a_i$,$g(a_i)$是固定的,重点在于最小化$g(y)-2*g(gcd(x,y))$
可以枚举$a_i$的因子$x$,用$f[x]$表示是$x$的倍数的$a[j]$使得$g[a[j]]$最小的数
因为要求$i≠j$,所以得维护最小值和次小值,时间复杂度$O(n\sqrt m+m)$ $m=\max{a_i}$
PS:今天BZOJ居然卡住了,管理员今天不在吗?
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define N 100010 6 #define M 1000010 7 int prime[M],tot,g[M]; 8 inline void pre(int t) 9 { 10 g[0]=1e9; 11 for(int i=2;i<=t;i++) 12 { 13 if(!g[i])prime[++tot]=i,g[i]=1; 14 for(int j=1;j<=tot&&i*prime[j]<=t;j++) 15 { 16 g[i*prime[j]]=g[i]+1; 17 if(!(i%prime[j]))break; 18 } 19 } 20 } 21 int n,a[N],f[M][2],maxn; 22 inline void update(int x,int i) 23 { 24 if(g[a[x]]<=g[a[f[i][0]]]) 25 f[i][1]=f[i][0],f[i][0]=x; 26 else if(g[a[x]]<=g[a[f[i][1]]]) 27 f[i][1]=x; 28 } 29 int main() 30 { 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++) 33 scanf("%d",&a[i]),maxn=max(a[i],maxn); 34 pre(maxn); 35 for(int i=n;i;i--) 36 { 37 for(int j=1;j*j<=a[i];j++) 38 if(!(a[i]%j)) 39 { 40 update(i,j); 41 if(j*j!=a[i]) 42 update(i,a[i]/j); 43 } 44 } 45 for(int i=1;i<=n;i++) 46 { 47 int ans=1e9,tmp=1e9; 48 for(int j=1;j*j<=a[i];j++) 49 if(!(a[i]%j)) 50 { 51 int k=j,x; 52 if(f[k][0]!=i)x=f[k][0]; 53 else x=f[k][1]; 54 int t=g[a[x]]-2*g[k]; 55 if(t<ans||(t==ans&&x<tmp)) 56 ans=t,tmp=x; 57 k=a[i]/j; 58 if(f[k][0]!=i)x=f[k][0]; 59 else x=f[k][1]; 60 t=g[a[x]]-2*g[k]; 61 if(t<ans||(t==ans&&x<tmp)) 62 ans=t,tmp=x; 63 } 64 printf("%d\n",tmp); 65 } 66 }
就让我永远不在这里写什么有意义的话--月下孤狼