BZOJ3837: [Pa2013]Filary

来源:互联网 发布:上古卷轴5清理脏数据 编辑:程序博客网 时间:2024/05/22 02:09

当m=2时,k至少为n/2
所以序列中的每一个位置都有至少1/2的概率在k个数中
随机一个序列的位置i,计算i在k个数中时,k的最大值
计算其他n-1个数和a[i]的差b[j],另外k-1个数的b[j]的gcd>1,那么将gcd分解质因数后,任意一个分解出来的p[i]都可以代表k个数
于是将b[j]分解质因数,维护每个p[i]在多少个b[j]中出现,最大的p[i]就是k,要计算m的最大值,容易发现m就是这k个b[j]的gcd,同时如果gcd的因子包含p[i],这k个数就是因子含p[i]的所有数(k要最大),即如果gcd取了p[i]就要取p[i]整除的所有数,对每个p[i]统计出现次数时顺便统计这些数的gcd,最大的就是m

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void up(int &x,const int &y){if(x<y)x=y;}int gcd(int a,int b){return !a?b:gcd(b%a,a);}const int maxn = 110000;const int maxp = 10000005;int p[1100000],pri,mp[maxp];bool v[maxp];void pre(){    for(int i=2;i<maxp;i++)    {        if(!v[i]) p[++pri]=i,mp[i]=i;        for(int j=1,k=p[j]*i;j<=pri;j++,k=p[j]*i)        {            if(k>=maxp) break;            v[k]=true; mp[k]=p[j];            if(i%p[j]==0) break;        }    }}int n,m;int b[maxn];int ti[maxp],s[maxp],num[maxp],ans,nowi,re1,re2;void upd(const int x,const int k){    if(ti[x]!=nowi) ti[x]=nowi,num[x]=s[x]=0;    num[x]++,s[x]=gcd(s[x],k);    if(num[x]>num[ans]) ans=x;    else if(num[x]==num[ans]&&s[x]>s[ans]) ans=x;}void divide(int x){    int tmp=x;    while(x>1)    {        int pp=mp[x];        while(mp[x]==pp) x/=pp;        upd(pp,tmp);    }}int main(){    pre();    //srand(time(0));    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",&b[i]);    for(nowi=1;nowi<=10;nowi++)    {        int i=rand()%n+1,tc=0; num[ans=0]=0;        for(int j=1;j<=n;j++)        {            int k=abs(b[i]-b[j]);            if(!k) tc++;            divide(k);        }        num[ans]+=tc;        if(num[ans]>re1) re1=num[ans],re2=s[ans];        else if(num[ans]==re1&&s[ans]>re2) re2=s[ans];    }    printf("%d %d\n",re1,re2);    return 0;}
原创粉丝点击