题意:给一个区间及一个K值,求区间内每一个a[i]^k的因子个数之和;
思路:已经知道一个数因子的个数就是其所有质因子幂次加一的连乘,所以题意就是求质因子的幂次,又知道区间大小为1e6但是大小达到1e12,因此要筛素数到1e6才可以满足,大概是8W的素数,此时发现复杂度达到了1e11,当然会超时,听大佬解惑后恍然大悟,其实这道题转换思维发现是二次筛法,我们把对每一个数去遍历素数表,变为用每一个素数去筛选区间的数,知道筛选的时候,只要找到第一个%prim[i]得数那么接下来每次不是跳一而是跳prim【i】,寻找第一个数取模即可找到,这样就防止了没有贡献的遍历;
代码如下:
1 #include<cstdio> 2 #include<cmath> 3 using namespace std; 4 typedef long long LL; 5 const int maxn=1e6+10; 6 const LL mod=998244353; 7 bool p[maxn]; 8 LL prim[maxn],m[maxn],x[maxn]; 9 int siever() 10 { 11 for(int i=0;i<1000;i++) 12 for(int k=(i<<1)+3,j=k*i+k+i;j<600000;j+=k) 13 p[j]=1; 14 int sp=1; 15 for(int i=0;i<600000;i++) 16 if(!p[i])prim[sp++]=(i<<1)+3; 17 prim[0]=2; 18 return sp; 19 } 20 int main() 21 { 22 freopen("input.txt","r",stdin); 23 int si=siever(); 24 int T; 25 for(scanf("%d",&T);T;T--) 26 { 27 LL l,r,k,ans=0; 28 scanf("%lld%lld%lld",&l,&r,&k); 29 int tol=0; 30 while(l<=r){x[tol]=1;m[tol++]=l++;} 31 LL q=sqrt(r),key=m[0]; 32 for(int i=0;i<si&&prim[i]<=q;i++) 33 { 34 int j=(key%prim[i]==0)?0:(prim[i]-key%prim[i]); 35 for(;j<tol;j+=prim[i]) 36 { 37 LL t=0; 38 while(m[j]%prim[i]==0){m[j]/=prim[i];t++;} 39 x[j]=x[j]*(t*k+1)%mod; 40 } 41 } 42 for(int j=0;j<tol;j++) 43 { 44 if(m[j]>1)x[j]=x[j]*(k+1)%mod; 45 ans=(ans+x[j])%mod; 46 } 47 printf("%lld ",ans); 48 } 49 return 0; 50 }