HDU 6069 Counting Divisors(多校4)

Problem Description

In mathematics, the function d(n) denotes the number of divisors of positive integer n.

For example, d(12)=6 because 1,2,3,4,6,12 are all 12’s divisors.

In this problem, given l,r and k, your task is to calculate the following thing :

(ri=ld(ik))mod998244353

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.

In each test case, there are 3 integers l,r,k(1lr1012,rl106,1k107) .

Output

For each test case, print a single line containing an integer, denoting the answer.

Sample Input

3
1 5 1
1 10 2
1 100 3

Sample Output

10
48
2302

题目大意

求[l,r]区间内每个数k次方的因子个数之和。

解题思路

首先要知道:
1、约数个数定理:
对于一个大于1的正整数n可以分解质因数: n=p1a1p2a2p3a3pkak ,则n的正约数的个数就是 f(n)=(a1+1)(a2+1)(a3+1)(ak+1)
由此定理可得 nk=p1ka1p2ka2p3ka3pkkak ,所以 nk 的正约数个数之和为 (ka1+1)(ka2+1)(ka3+1)(kak+1)
2、埃拉托斯特尼筛法:
要得到自然数n以内的全部素数,必须把不大于 n 的所有素数的倍数剔除,剩下的就是素数。
由此定理我们便可以得到解题的大致思路,由于l,r的取值范围最大到 1012 ,所以我们可以先用素数筛法打表求出 1012=106 内的所有素数,然后枚举每一个素数i,计算每个素数对区间l~r任一数的贡献值,即判断从l~r中的任一数是不是 i 的倍数,若是,则该倍数对应着约数个数定理中的ai(指数),按照公式求解即可。
将表中每一个素数遍历完之后,若仍有值不为1的情况,根据埃拉托斯特尼定理可得该剩余的数即为素数,且其对应的ai=1,带入公式。
将l~r每个数求得的结果分别相加即为最终答案。

代码实现

#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define maxn 1000006
#define mod 998244353
#define ll long long
int prime[maxn],num=0;
ll sum[maxn],a[maxn];
bool visit[maxn];
void getprime()
{
    int i;
    memset(visit,0,sizeof(visit));
    for(i=2; i<maxn; i++)
    {
        if(!visit[i])
        {
            prime[num++]=i;
            for(int j=i+i; j<maxn; j+=i)
                visit[j]=1;
        }
    }
}
int main()
{
    int T;
    ll l,r,k;
    scanf("%d",&T);
    getprime();
    while(T--)
    {
        ll ans=0;
        scanf("%lld %lld %lld",&l,&r,&k);
        for(int i=0;i<=r-l;i++) sum[i]=1,a[i]=i+l;
        for(int i=0;i<num;i++)
        {
            ll t=(l/prime[i]+(l%prime[i]?1:0))*prime[i];  //因为+运算符优先级高于?: 所以三目运算符外必须要有括号
            for(ll j=t;j<=r;j+=prime[i])
            {
                int countt=0;
                while(a[j-l]%prime[i]==0)
                {
                    countt++;
                    a[j-l]/=prime[i];
                }
                sum[j-l]=(sum[j-l]*(countt*k+1)%mod)%mod;
            }
        }
        for(int i=0;i<=r-l;i++)
        {
            if(a[i]!=1)
                sum[i]=((sum[i]*(k+1))%mod)%mod;
            ans=(ans+sum[i]%mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值