题目: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; }