zoukankan      html  css  js  c++  java
  • bzoj 3481 DZY Loves Math III——反演+rho分解质因数

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3481

    推推式子发现:令Q=gcd(P,Q),ans=Σ(d|Q) d*phi(P/d)。把 d 质因数分解,设 t 为 Q 的指数, w 为 P 的指数,ans变成每个质数的 Σ(i=0~t) p^i * phi( p^(w-i) ) 连乘。

    分解质因数用 Pollar Rho 。

    注意 Q=0 就是 Q=P,要特判!而且不要以为答案变成  (!x || !y) 了!

    d从0到P-1 就是 d从1到P!不要特判 P==Q时给答案减P !因为算的时候就没算d=0的!

    每个质数的那个式子可以化简,把 phi 写开,和 p^i 合并,就不用枚举 i 。但要注意 w-i ==0 时 phi 的式子有些不同了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #define ll long long
    using namespace std;
    const int N=650,mod=1e9+7;
    int n,ans=1,c[N],c2[N],tot;
    ll p[N],P=1;
    bool vis[N],flag;
    ll rdl()
    {
      ll ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9') ret=(ret<<3ll)+(ret<<1ll)+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    void upd(ll &x,ll md){x-=(x>=md?md:0);}
    ll mul(ll a,ll b,ll md)
    {
      ll ret=0;//0!
      while(b)
        {
          if(b&1ll)ret=ret+a,upd(ret,md);
          a=a+a,upd(a,md);b>>=1ll;
        }
      return ret;
    }
    ll pw(ll x,ll k,ll md)
    {
      ll ret=1;
      while(k)
        {
          if(k&1ll)ret=mul(ret,x,md);
          x=mul(x,x,md);k>>=1ll;
        }
      return ret;
    }
    int phi(ll p,int k)
    {
      if(!k) return 1;
      return mul(p-1,pw(p,k-1,mod),mod);
    }
    void add(ll a,bool flag)
    {
      if(flag)
        {
          for(int i=1;i<=tot;i++)
        if(p[i]==a)
          { c[i]++;return;}
          p[++tot]=a; c[tot]=1;
        }
      else
        {
          for(int i=1;i<=tot;i++)
        if(p[i]==a&&c2[i]<c[i])
          c2[i]++;//Q=gcd()
        }
    }
    bool ml_rb(ll n)
    {
      if(n<2)return false;if(n==2)return true;if((n&1)==0)return false;
      ll u=n-1,t=0;
      while((u&1)==0){u>>=1,t++;}
      int s=20;
      while(s--)
        {
          ll a=rand()%(n-2)+2;//2~n-1
          a=pw(a,u,n); ll pre=a;
          for(int i=1;i<=t;i++)
        {
          a=mul(a,a,n);
          if(a==1&&pre!=1&&pre!=n-1)return false;
          pre=a;
        }
          if(a!=1) return false;
        }
      return true;
    }
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll pl_rho(ll x,ll c)
    {
      ll x0=rand()%x,y0=x, k=1,i=0;
      while(1)
        {
          x0=(mul(x0,x0,x)+c)%x;
          ll g=gcd(abs(x0-y0),x);
          if(g!=1&&g!=x) return g;
          if(x0==y0)return x;
          if((++i)==k){k<<=1;y0=x0;}
        }
    }
    void fd_fac(ll n,bool flag)
    {
      if(n<2)return;
      if(ml_rb(n))
        {
          add(n,flag);return;
        }
      ll p=n;
      while(p==n)p=pl_rho(p,rand()%(n-1)+1);
      fd_fac(p,flag); fd_fac(n/p,flag);
    }
    int main()
    {
      srand(time(0));  n=rdl();
      for(int i=1;i<=n;i++)
        {
          ll a=rdl(); P=mul(P,a,mod);
          fd_fac(a,1);
        }
      for(int i=1;i<=n;i++)
        {
          ll a=rdl(); if(!a){flag=1;continue;}
          if(flag)continue;
          fd_fac(a,0);
        }
      if(flag)for(int i=1;i<=tot;i++)c2[i]=c[i];
      for(int i=1,d,tp;i<=tot;i++)
        {
          tp=pw(p[i],c[i]-1,mod);
          d=mul(tp,mul(p[i]-1,c2[i]+1,mod)+(c[i]==c2[i]),mod);
          ans=mul(ans,d,mod);
        }
      printf("%d
    ",ans);
      return 0;
    }
  • 相关阅读:
    什么是 Visual VM?
    myeclipse svn 修改用户名和密码
    unix/linux共享内存应用与陷阱
    linux内存查看方式
    Linux下crontab命令的用法
    linux ftp命令参数全集
    XmlDataSource控件绑定GridView
    VC++发布Activex控件
    SqlServer数据库自定义Split()函数
    C和C++中的主要数据类型和字节大小
  • 原文地址:https://www.cnblogs.com/Narh/p/9753293.html
Copyright © 2011-2022 走看看