CF364D Ghd(隨機化)
阿新 • • 發佈:2019-01-04
另一個集合\(s\)的\(ghd\)為\(max\{gcd(s')||s'|>=0.5|s|\}\) 給定序列\(a\),求\(ghd\)
隨機化演算法。因為\(|s'|\geq 0.5|S|\),所以每個元素在\(s'\)中的概率為\(0.5\),我們可以欽定一個元素令它在\(s'\)中,那麼算出它和其他所有元素的\(\gcd\),用\(map\)將所有的\(\gcd\)存起來,\(first\)存值,\(second\)存這個值的出現次數。然後從大到小列舉每一個\(\gcd\),並把比它大的那些且是它倍數的\(\gcd\)的出現次數加起來,如果某一次某個\(\gcd\)出現次數大於一半,那麼該答案可行
為了避免TLE加幾發剪枝,比如如果隨機出來的元素比最優答案小就無視,如果兩個數的\(\gcd\)比最優答案小無視,從大到小列舉元素只要有一個答案成立剩下的全都可以無視。然後\(rand\)個\(15\)次左右基本就能出答案了
//minamoto #include<bits/stdc++.h> #define R register #define ll long long #define fi first #define se second #define IT map<ll,int>::iterator #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i) #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) using namespace std; char buf[1<<21],*p1=buf,*p2=buf; inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} ll read(){ R ll res,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f; } char sr[1<<21],z[20];int C=-1,Z=0; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} void print(R int x){ if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } const int N=1e6+5; ll a[N],ans=1,x;int n,pos;map<ll,int>mp; ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} int main(){ // freopen("testdata.in","r",stdin); srand(time(0)); n=read(); fp(i,1,n)a[i]=read(); fp(T,1,15){ pos=(1ll*rand()*RAND_MAX+rand())%n+1; if(a[pos]<=ans)continue; fp(i,1,n){ x=gcd(a[pos],a[i]);if(x<=ans)continue; mp.count(x)?++mp[x]:mp[x]=1; }if(mp.empty())continue; IT it=mp.end(); do{ --it;if(it->fi<=ans)break; int cnt=0; for(IT itl=it;itl!=mp.end()&&(cnt<<1)<n;++itl) if(itl->fi%it->fi==0)cnt+=itl->se; if((cnt<<1)>=n){ans=it->fi;break;} }while(it!=mp.begin()); map<ll,int>().swap(mp); }printf("%I64d\n",ans); return 0; }