hdu 6069 Counting Divisors

题意:给一个区间及一个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\n",ans);
48     }
49     return 0;
50 }

 

posted @ 2017-08-03 22:06  MeowMeowMeow  阅读(154)  评论(0编辑  收藏  举报