2017 Multi-University Training Contest - Team 4 3.Counting Divisors(数论)
链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1003&cid=762
题意:记d(n)为n的因子个数,给定l,r,k,求∑d(i^k),(i=l,l+1,...,r)。
分析:记n=(p1^a1)*(p2^a2)*...*(pt^at),显然d(n^k)=∏(k*ai+1),(i=1,2,...,t),而且d(n)是个积性函数,可以想到用线性筛搞一下,然而数据范围10^12。。先筛10^6以内的质数p,然后枚举p在[l,r]以内的倍数,把倍数除尽p,假设除了m次,就乘一个k*m+1,如果最后有的数没有被除成1,就再乘一个k+1,再把所有结果加起来就是答案了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const int mod=998244353; 7 int pri[100000],len=0,ans[1000005]; 8 ll m[1000005],l,r; 9 int k,res; 10 void CalPri(){ 11 int maxp=1000005; 12 bool Is_pri[maxp]; 13 memset(Is_pri,-1,sizeof(Is_pri)); 14 for(int i=2;i<maxp;i++){ 15 if(Is_pri[i]){ 16 pri[len++]=i; 17 // d[i]=k+1; 18 } 19 for(int j=0;j<len&&(ll)i*pri[j]<maxp;j++){ 20 Is_pri[i*pri[j]]=false; 21 if(i%pri[j]==0){ 22 // int q=i,c=1; 23 // while(q%pri[j]==0){c++;q/=pri[j];} 24 // d[i*pri[j]]=((ll)d[q]*(k*c+1))%mod; 25 break; 26 } 27 28 } 29 } 30 } 31 void solve(){ 32 for(int i=0;i<=r-l;i++){ 33 ans[i]=1; 34 m[i]=i+l; 35 } 36 for(int i=0;i<len&&pri[i]<=r;i++){ 37 int p=pri[i]; 38 for(ll j=(ll)((l-1)/p+1)*p;j<=r;j+=p){ 39 int c=0; 40 while(m[j-l]%p==0){c++;m[j-l]/=p;} 41 ans[j-l]=((ll)ans[j-l]*(k*c+1))%mod; 42 } 43 } 44 res=0; 45 for(int i=0;i<=r-l;i++){ 46 if(m[i]!=1) 47 ans[i]=((ll)ans[i]*(k+1))%mod; 48 res=(res+ans[i])%mod; 49 } 50 } 51 int test(){ 52 int a=0; 53 for(ll i=l;i<=r;i++){ 54 ll n=i,q=1; 55 for(int j=0;j<len;j++){ 56 int p=pri[j],c=0; 57 while(n%p==0){ 58 n/=p;c++; 59 } 60 q=(q*(c*k+1))%mod; 61 } 62 if(n!=1)q=(q*(k+1))%mod; 63 a=(a+q)%mod; 64 } 65 return a; 66 } 67 int main(){ 68 //freopen("e:\\in.txt","r",stdin); 69 CalPri(); 70 int t; 71 scanf("%d",&t); 72 while(t--){ 73 int ans=0; 74 cin>>l>>r>>k; 75 solve(); 76 printf("%d\n",res); 77 } 78 return 0; 79 }