HDU6069 Counting Divisors(区间素数筛)

来源:互联网 发布:软件著作权技术特点 编辑:程序博客网 时间:2024/06/02 06:16
#include<cstdio>#include<cstring>#include<iostream>using namespace std;/*区间素数筛法求区间[l^k,r^k]每个数质因数个数的和,mod 998244353(1<=l<=r<=1e12,r-l<=1e6,1<=k<=1e7)*/typedef long long LL;const int maxn=1e6+5;const int maxm=1e7+5;const int mod=998244353;bool is_prime[maxm];bool is_prime_small[maxm];int p;LL sum[maxn];//当前这个数因数的个数LL cnt[maxn];//区间中的每个数//区间筛法,处理的区间范围为[a,b)void segment_sieve(LL a, LL b, LL k){    for(int i=0; (LL)i*i<b; i++) is_prime_small[i]=true;    for(int i=0; i<b-a; i++) is_prime[i]=true;    for(int i=2; (LL)i*i<b; i++)//i是素数    {        if(is_prime_small[i])        {            for(int j=2*i; (LL)j*j<b; j+=i) is_prime_small[j]=false;//筛[a,sqrt(b))            LL v;//左区间            if(a%i==0)            {                v=a;            }            else            {                v=(a+i-1)/i*i;            }            for(LL j=v; j<b; j+=i)            {                LL ret=0;                while(cnt[j-a]%i==0)//质因数分解                {                    ret++;                    cnt[j-a]/=i;                }                sum[j-a]=sum[j-a]*(k*ret%mod+1)%mod;            }        }    }    for(LL i=0; a+i<b; i++)//分解的数是质数    {        if(cnt[i]>1) sum[i]=sum[i]*(1LL*k+1)%mod;    }}int main(){    int T;    LL l,r,k;    scanf("%d",&T);    while(T--)    {        scanf("%I64d%I64d%I64d",&l,&r,&k);        for(LL i=0; i+l<=r; i++)//不能直接按照l,r下标存        {            cnt[i]=i+l;//r-l的差较小            sum[i]=1;        }        segment_sieve(l,r+1,k);//处理的范围为[l,r],所以r+1        LL ans=0;        for(LL i=0; i+l<=r; i++)        {            ans=(ans+sum[i])%mod;        }        printf("%I64d\n",ans);    }    return 0;}
原创粉丝点击