zoukankan      html  css  js  c++  java
  • CF 757E Bash Plays with Functions——积性函数+dp+质因数分解

    题目:http://codeforces.com/contest/757/problem/E

    f0[n]=2^m,其中m是n的质因子个数(种类数)。大概是一种质因数只能放在 d 或 n/d 两者之一。

    然后应该发现因为 f0 是积性的,所以 fr 也是积性的!因为是卷积得来的。

    这样就能把每个质因数分开。对于每种质因数考虑 fr 的转移,则 f [ r ][ p^k ] = sigma(i:0~k) ( f [ r-1 ][ p^i ] ) 。

    应该发现 f0 里每种质因数的值只和其次数有关,从转移可得出 f [ k ] 里的各种质因数的值也只和其次数有关!所以 dp 状态里只要记录次数就行。

    学习到了质因数分解的更好而同样简单的方法。就是预处理mindiv,然后每次除以自己的mindiv。

    先写了自己的原始方法,T了;于是怒写了个pollar rho,结果T得更快,难道是写错了?

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e6,M=20,mod=1e9+7;
    int q,r,n,dp[N+5][M+5],s[M+5],ans,mindiv[N+5],cnt,pri[N+5];
    bool vis[N+5];
    int rdn()
    {
      int 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<<3)+(ret<<1)+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    void upd(int &x){x-=(x>=mod?mod:0);}
    void init()
    {
      mindiv[1]=1;//
      for(int i=2;i<=N;i++)
        {
          if(!vis[i])pri[++cnt]=i,mindiv[i]=i;
          for(int j=1;j<=cnt&&(ll)i*pri[j]<=N;j++)
        {
          int d=i*pri[j];
          vis[d]=1; mindiv[d]=pri[j];
          if(i%pri[j]==0)break;
        }
        }
    }
    int pw(int x,int k,int md)
    {
      int ret=1;while(k){if(k&1)ret=(ll)ret*x%md;x=(ll)x*x%md;k>>=1;}return ret;
    }
    bool MR(int x)
    {
      if(x==2)return true;
      int s=20,u=x-1,t=0;
      while((u&1)==0)u>>=1,t++;
      while(s--)
        {
          int a=rand()%(x-2)+2;//2~x-1
          a=pw(a,u,x);
          for(int i=1,d;i<=t;i++)
        {
          d=(ll)a*a%x;
          if(d==1&&a!=1&&a!=x-1)return false;
          a=d;
        }
          if(a!=1)return false;
        }
      return true;
    }
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int Pl_rho(int x,int c)
    {
      int x0=rand()%x,y=x,t=1,k=0;
      while(1)
        {
          x0=((ll)x0*x0+c)%(x+1);
          int g=gcd(abs(x0-y),x);
          if(g!=1&&g!=x)return g;
          if(x0==y)return x;
          if(++k==t)t<<=1,y=x0;
        }
    }
    void fd_fc(int x)
    {
      if(x<2)return;
      if(MR(x))
        {
          int ret=0;
          while(n%x==0)n/=x,ret++;
          ans=(ll)ans*dp[r][ret]%mod;
          return;
        }
      int p=x;
      while(p==x)p=Pl_rho(p,rand()%(x-1)+1);//1~x-1
      fd_fc(p); fd_fc(x/p);
    }
    int main()
    {
      dp[0][0]=1;s[0]=1; init();
      for(int i=1;i<=M;i++)dp[0][i]=2,s[i]=s[i-1]+2;
      for(int i=1;i<=N;i++)
        for(int j=0;j<=M;j++)
          dp[i][j]=s[j],s[j]=s[j-1]+dp[i][j],upd(s[j]);
      q=rdn();
      while(q--)
        {
          r=rdn(); n=rdn(); ans=1;
          //fd_fc(n);
          while(n!=1)
        {
          int i=mindiv[n],d=0;
          while(n%i==0)n/=i,d++;
          ans=(ll)ans*dp[r][d]%mod;
        }
          /*
          for(int i=mindiv[n],d;(ll)i*i<=n;i++)
        if(n%i==0)
          {
            d=0;
            while(n%i==0)d++,n/=i;
            ans=(ll)ans*dp[r][d]%mod;
          }
          if(n>1)ans=(ll)ans*dp[r][1]%mod;
          */
          printf("%d
    ",ans);
        }
      return 0;
    }
  • 相关阅读:
    终端创建scrapy项目时报错(转)
    redis的一些命令
    pom.xml中build标签
    spring与mybatis四种整合方法
    linux lsof/netstat查看进程和端口号相关命令:
    ps -ef |grep 输出的具体含义
    java web项目在linux部署、启动,查看系统配置常用的linux命令总结
    linux mysql操作命令大全
    mysql中between...and..的使用,及时间范围的查询
    mysql中if()函数使用
  • 原文地址:https://www.cnblogs.com/Narh/p/9776781.html
Copyright © 2011-2022 走看看