1. 程式人生 > >bzoj 3837 (隨機過題法了解一下)

bzoj 3837 (隨機過題法了解一下)

name mit rac problems ack content alt pre 大於等於

3837: [Pa2013]Filary

Time Limit: 60 Sec Memory Limit: 256 MB
Submit: 395 Solved: 74
[Submit][Status][Discuss]

Description

給定n個正整數,從中挑出k個數,滿足:存在某一個m(m>=2),使得這k個數模m的余數相等。 求出k的最大值,並求出此時的m。如果有多組解使得k最大,你要在此基礎上求出m的最大值。

Input

第一行一個正整數n(2<=n<=10^5)。 第二行n個正整數w[i](1<=w[i]<=10^7)。保證不會出現所有w[i]都相等的情況。

Output

一行兩個整數k,m。保證答案存在。

Sample Input

6
7 4 10 8 7 1

Sample Output

5 3

HINT


聽說大家都喜歡隨機過題法,於是我切一道(正解是)隨機的題目漲漲姿勢。 首先此題在k==2 的時候最小是 $ \frac{n}{2} $ 的,以此類推 k==3 時是 $ \frac{n}{3} $等等。 那麽最小的情況是大於等於$ \frac{n}{2} $的,這點毋庸置疑。 那麽我們隨機一個位置pos,假設a[pos]在這k個數中,找最大的k。 那麽我們求a[pos]和每個位置i的差值b[i],然後我們這k個數的 $ gcd \gt 1 $ 這個毋庸置疑。那麽我們把每個b[i]分解成一堆質數,並記錄每個質數出現的位置數。那麽最大的k就是質數出現的最大位置數。k對應的最大的m就是這些位置的數的gcd。 而據cls說這個隨機期望是logn的。不過你還是多隨機個四五次取最大,這樣才保險點。 技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define INF 0x3f3f3f3f
 5 #define LL long long
 6 #define pb push_back
 7 #define mod 1000000007
 8 #define ls(i) (i<<1)
 9 #define rs(i) (i<<1|1)
10 #define mp make_pair
11 #define
fi first 12 #define se second 13 using namespace std; 14 const int N=1e7+10; 15 const int M=1e5+10; 16 int inf[N],prime[N],pre[N],g[N],num[N]; 17 int tot; 18 int gcd(int a,int b) 19 { 20 int c; 21 while(b) 22 c=a%b,a=b,b=c; 23 return a; 24 } 25 void init() 26 { 27 tot=0; 28 int n=10000000; 29 for(int i=2;i<=n;i++) 30 { 31 if(!inf[i]) 32 prime[++tot]=i,pre[i]=tot; 33 for(int j=1;j<=tot && prime[j]*i<=n;j++) 34 { 35 inf[prime[j]*i]=1; 36 pre[prime[j]*i]=j; 37 if(i%prime[j]==0) break; 38 } 39 } 40 return ; 41 } 42 int a[M],b[M]; 43 int main() 44 { 45 init(); 46 int n,m,k; 47 scanf("%d",&n); 48 for(int i=1;i<=n;i++) 49 scanf("%d",a+i); 50 int p=log10(n)+5; 51 srand(time(0)); 52 m=k=0; 53 while(p--) 54 { 55 56 int pos=rand()%n+1; 57 int tmp=0; 58 int minm=0,mink=0; 59 for(int i=1;i<=n;i++) 60 { 61 b[i]=abs(a[i]-a[pos]); 62 if(!b[i]) 63 tmp++; 64 } 65 for(int i=1;i<=n;i++) 66 { 67 int t=b[i]; 68 while(t && t!=1) 69 { 70 int temp=pre[t]; 71 num[temp]++,g[temp]=gcd(g[temp],b[i]); 72 if(mink<num[temp]) mink=num[temp],minm=g[temp]; 73 else if(mink==num[temp]) minm=max(g[temp],minm); 74 while(t%prime[temp]==0) t/=prime[temp]; 75 } 76 } 77 if(mink+tmp>k) k=mink+tmp,m=minm; 78 else if(mink+tmp==k) m=max(m,minm); 79 for(int i=1;i<=n;i++) 80 { 81 int t=b[i]; 82 while(t && t!=1) 83 { 84 int temp=pre[t]; 85 num[temp]=0,g[temp]=0; 86 while(t%prime[temp]==0) t/=prime[temp]; 87 } 88 } 89 } 90 printf("%d %d\n",k,m); 91 return 0; 92 }
View Code

bzoj 3837 (隨機過題法了解一下)