首页 > 代码库 > BZOJ2082 : [Poi2010]Divine divisor

BZOJ2082 : [Poi2010]Divine divisor

将所有数分解质因数,那么第一问就是求指数的最大值,第二问就是$2^{指数最大的质数个数}-1$。

首先将$10^6$以内的质因数全部找到,那么剩下部分的因子$>10^6$,且只有3种情况:

1.大质数

2.大质数的平方

3.两个大质数的乘积

对于1可以用MillerRabin算法判定,对于2可以尝试开根号然后判定。

那么剩下的一定是3,对于每个不确定的数字,如果它所含的因子只有它有,那么这两个因子可以合并,算第二问的时候个数$+=2$即可。

判断其它数字是否也有这个因子,只需要求gcd即可。

时间复杂度$O(\frac{nv^{\frac{1}{3}}}{\ln v})$。

 

#include<cstdio>#include<cmath>#include<algorithm>#include<cstdlib>using namespace std;typedef long long ll;const int N=1000000,B=10000,MAXL=220;int n,i,j,k,tot,p[N],v[N],ca,cb,cc,ans0,ans1;ll a[64*600],b[610],c[610];inline ll gcd(ll a,ll b){  ll c=1;  while(a-b){    if(a&1){      if(b&1){        if(a>b)a=(a-b)>>1;else b=(b-a)>>1;      }else b>>=1;    }else{      if(b&1)a>>=1;else c<<=1,a>>=1,b>>=1;    }  }  return c*a;}inline ll mul(ll a,ll b,ll n){return(a*b-(ll)(a/(long double)n*b+1e-3)*n+n)%n;}inline ll pow(ll a,ll b,ll n){  ll d=1;a%=n;  while(b){    if(b&1)d=mul(d,a,n);    a=mul(a,a,n);    b>>=1;  }  return d;}inline bool check(ll a,ll n){  ll m=n-1,x,y;int i,j=0;  while(!(m&1))m>>=1,j++;  x=pow(a,m,n);  for(i=1;i<=j;x=y,i++){    y=pow(x,2,n);    if((y==1)&&(x!=1)&&(x!=n-1))return 1;  }  return y!=1;}inline bool miller_rabin(ll n){  int t=5;ll a;  if(!(n&1))return 0;  while(t--)if(check(rand()%(n-1)+1,n))return 0;  return 1;}inline ll getsqrt(ll n){  ll x=sqrt(n);  for(ll i=x-2;i<=x+2;i++)if(i*i==n)return i;  return 0;}inline void divide(){  ll n;  scanf("%lld",&n);  for(int i=0;i<tot&&p[i]<=n;i++)while(n%p[i]==0)n/=p[i],a[++ca]=p[i];  if(n==1)return;  if(miller_rabin(n)){a[++ca]=c[++cc]=n;return;}  ll t=getsqrt(n);  if(t){a[++ca]=t;a[++ca]=c[++cc]=t;return;}  b[++cb]=n;}inline void solve(ll n){  for(int i=1;i<=cc;i++)if(n%c[i]==0){    a[++ca]=c[i],a[++ca]=n/c[i];    return;  }  for(int i=1;i<=cb;i++){    ll t=gcd(n,b[i]);    if(t==1||t==n)continue;    a[++ca]=t,a[++ca]=n/t;    return;  }  a[++ca]=-n;}struct Num{  int a[MAXL],len,fu;  Num(){len=1,fu=a[1]=0;}  Num operator+(const Num&b){    Num c;    c.len=max(len,b.len)+2;    int i;    for(i=1;i<=c.len;i++)c.a[i]=0;    if(fu==b.fu){      for(i=1;i<=len;i++)c.a[i]=a[i];      for(i=1;i<=b.len;i++)c.a[i]+=b.a[i];      for(i=1;i<=c.len;i++)if(c.a[i]>=B)c.a[i+1]++,c.a[i]-=B;      while(c.len>1&&!c.a[c.len])c.len--;      c.fu=fu;    }else{      bool flag=0;      if(len==b.len){        for(i=len;i;i--)if(a[i]!=b.a[i]){          if(a[i]>b.a[i])flag=1;          break;        }      }else{        if(len>b.len)flag=1;      }      if(flag){        for(i=1;i<=len;i++)c.a[i]=a[i];        for(i=1;i<=b.len;i++)c.a[i]-=b.a[i];        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=B;        while(c.len>1&&!c.a[c.len])c.len--;        c.fu=fu;      }else{        for(i=1;i<=b.len;i++)c.a[i]=b.a[i];        for(i=1;i<=len;i++)c.a[i]-=a[i];        for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=B;        while(c.len>1&&!c.a[c.len])c.len--;        c.fu=b.fu;      }    }    return c;  }  void write(){    printf("%d",a[len]);    for(int i=len-1;i;i--)printf("%04d",a[i]);  }  void set(int x){    if(x<0){a[len=1]=fu=1;return;}    fu=0,a[len=1]=x;  }}num,sub;int main(){  for(i=2;i<N;i++){    if(!v[i])p[tot++]=i;    for(j=0;j<tot&&i*p[j]<N;j++){      v[i*p[j]]=1;      if(i%p[j]==0)break;    }  }  scanf("%d",&n);  while(n--)divide();  for(i=1;i<=cb;i++)solve(b[i]);  sort(a+1,a+ca+1);  for(i=1;i<=ca;i=j){    for(j=i;j<=ca&&a[i]==a[j];j++);    k=j-i,tot=a[i]<0?2:1;    if(k>ans0)ans0=k,ans1=tot;else if(k==ans0)ans1+=tot;  }  printf("%d\n",ans0);  num.set(1);  while(ans1--)num=num+num;  sub.set(-1);  num=num+sub;  num.write();  return 0;}

  

BZOJ2082 : [Poi2010]Divine divisor