HDU_6069 Counting Divisors

题目链接
题目意思

给你三个数L,R,K让你求满足下面公式的答案


这里写图片描述

解题思路

由题意我们可以知道L,R最大为1e12,所以我们可以用筛法筛选sqrt(1e12)之内的所有素数。
有数论中的结论我们知道,任何一个正整数x,都可以分解成若干个素数幂的积。
则 x = (p1^m1)* (p2^m2)* (p3^m3)* …..* (pn^mn); 其中p1,p2,p3…pn都是素数,m1,m2,m3…mn都是幂指数。
则 x 的因子个数d(x) = (m1+1)* (m2+1)*(m3+1)….(mn+1);

那么对于x^k = ((p1^m1)* (p2^m2)* (p3^m3)* …..*(pn^mn))^k;
则 x^k = (p1^m1* k) * (p2^m2* k) * (p3^m3* k)* …..* (pn^mn*k);
则x^k的因子个数d(x^k) = (m1* k+1) * (m2* k+1) * (m3* k+1) * …..(mn k+1);

然后这道题就是让算一个区间的K次方的因数个数之和,首先先将1e6之内的素数打表,然后再然后枚举这些素数,在枚举 [L,R] 区间中这些素数的倍数,然后根据这些倍数进行素因子分解,其实就是统计 [L,R] 区间中有多少个枚举的素数,然后乘以 K, 在加 1 计算即可。在枚举 [L,R] 区间值的时候,我们需要先把 [L,R] 区间中的数用数组保存下来,然后通过数组进行素因子分解。

代码部分
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 998244353;
const LL MAXN = 1e6+5;
int prime[MAXN], cnt;///cnt代表1e6中素数的个数
LL p[MAXN];///存放素数从0开始
///筛法求素数
void isprime()
{
    memset(prime, 0, sizeof(prime));
    cnt = 0;
    prime[1] = 1;
    for(LL i=2; i<MAXN; i++)
    {
        if(!prime[i])
        {
            p[cnt++] = i;
            for(LL j=i*i; j<MAXN; j+=i)
                prime[j] = 1;
        }
    }
}

LL f[MAXN], num[MAXN];///f[i]用来存储L~R之间的数,在不断的对因数相除。累积数量
int main()
{
    isprime();
    int T;
    scanf("%d", &T);
    while(T--)
    {
        LL L, R, K;
        scanf("%lld%lld%lld", &L, &R, &K);
        LL ans = 0;
        if(L == 1) 
            ans = 1, L++;
        int t = R-L;
        for(int i=0; i<=t; i++) 
            f[i] = i+L, num[i] = 1;///初始化

        for(int i=0; i<cnt&&p[i]*p[i]<=R; i++)
        {
            LL tmp = L;
            if(L % p[i]) tmp = (L/p[i]+1)*p[i];///找到第一个可以整除素数p[i]的数,不进行这步会超时
            //cout << "tmp = " << tmp << endl;
            for(LL j=tmp; j<=R; j+=p[i])///素因子分解
            {
                LL cnt = 0;
                while(f[j-L]%p[i] == 0)
                {
                    cnt++;
                    f[j-L] /= p[i];
                }
                num[j-L] = num[j-L]*(cnt*K+1)%MOD;
            }
        }


        for(int i=0; i<=t; i++)///计算结果
        {
            //cout << "num = " << num[i] << "   f = " << f[i] << endl;
            if(f[i] == 1) 
                ans = (ans + num[i]) % MOD;
            else
                ans = (ans + num[i]*(K + 1)) % MOD;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值