HDU 6069 Counting Divisors (素因子求贡献)

该博客介绍了一道HDU 2017多校赛的数论问题,要求计算在给定区间[l, r]内,所有数的因子数关于k的贡献。通过素因子分解和线性筛方法,可以以O(∑ri=lΩ(i))的时间复杂度解决,其中Ω(i)表示i的素因子数量。" 124734470,7710067,Linux磁盘分区与挂载详细教程,"['Linux', '磁盘管理', '文件系统']
摘要由CSDN通过智能技术生成

数论 素数 素分解 贡献 HDU 2017多校赛

Description

给定 l r k ,计算以下表达式的值。

i=lrd(ik)mod998244535

其中 d(n) n 的正因子数量。

Input

第一行给出用例组数T,接下来 T 行,每行给出三个整数l r k 1lr1012, rl106, 1k107

Output

对于每组测试用例,输出一个整数表示答案。

Sample Input

3
1 5 1
1 10 2
1 100 3

Sample Output

10
48
2302

Solution

易知若 n 的素因子分解为n=pk11pk22pkss,则 d(n)=(k1+1)(k2+1)(ks+1) d(nk)=(kk1+1)(kks+1)(kks+1) 。因此要得到 ik 的因子数只需要素因子分解 i

一个数n的素因子主要分布在[1,n]的范围内, [n,n] 内最多有一个。反证:假设 [n,n] 有两个素因子 p q,则 p×qn ,矛盾。

区间 [l,r] 内每个数的素因子,主要分布在 [1,r] 内, [r,r] 内最多有一个。于是线性筛出 [1,r] 范围内的所有质数,枚举每个质数 p ,枚举 [l,r] 内所有 p 的倍数,计算 p 对它们的全部贡献。然后枚举 [l,r] 内的每个数,如果在 [r,r] 内还有素因子,一并算上。

时间复杂度为 O(ri=lΩ(i)) ,其中 Ω(i) i <script id="MathJax-Element-74" type="math/tex">i</script>的素因子数量。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
const int N = 1e6 + 10;

int is_prime[N], prime[N], tot;
void get_prime(int n)
{
    for (int i = 1; i <= n; i++) is_prime[i] = true;
    is_prime[0] = is_prime[1] = false;
    tot = 0;
    for (int i = 2; i <= n; i++)
    {
        if (is_prime[i]) prime[tot++] = i;
        for (int j = 0; j < tot && prime[j] * i <= n; j++)
        {
            is_prime[prime[j] * i] = false;
            if (i % prime[j] == 0) break;
        }
    }
}

ll a[N], d[N];

int main()
{
    int T;
    scanf("%d", &T);
    get_prime(1e6);
    while (T--)
    {
        ll l, r, k;
        scanf("%lld%lld%lld", &l, &r, &k);
        for (ll i = l; i <= r; i++) a[i - l] = i, d[i - l] = 1;;
        for (int i = 0; i < tot; i++)
        {
            ll p = prime[i];
            ll t = ceil((double)l / p) * p;
            for (ll j = t; j <= r; j += p)
            {
                int tot = 0;
                while (a[j - l] % p == 0) tot++, a[j - l] /= p;
                d[j - l] = d[j - l] * (tot * k % mod + 1) % mod;
            }
        } 
        ll ans = 0;
        for (ll i = l; i <= r; i++)
        {
            if (a[i - l] != 1) d[i - l] = d[i - l] * (k + 1) % mod;
            ans = (ans + d[i - l]) % mod;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6069

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值