【数论】hdu 6069 Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2815    Accepted Submission(s): 1040
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 :

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(1≤l≤r≤1012,r−l≤106,1≤k≤107).
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

题意:d(i):i 的因子个数,给定范围内任意l,r,k 计算如上公式值;
思路:d(i),把 i 分解为质因子的形式,然后各个质因子的幂+1,然后相乘,就是 i 的因子个数;
开一个数组来保存1~1e6的质数,1e6范围内的质数就够用了;
之前的代码是把 l , r 的循环放在外部,质数的循环放在内部,用来求每一个数的不同质因子的个数,这样的复杂度是n* tot(质数的个数)
把质数的循环放在外部的话,可以优化:
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

#define ll long long
#define mod 998244353

const int N=1000006;

int is_prime[N+10],prime[N+10];
int tot=0;
ll ans;

ll l,r,k;

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

ll f[N],g[N];
void work()
{
    for(ll i=l; i<=r; i++)
        f[i-l]=i,g[i-l]=1;

    for(int i=0; i<tot; i++)
    {
        if(prime[i]*prime[i]>r) // 优化 ,如果这个素数的平方都大于r,那么l~r没有能够整除这个素数和这个素数之后的所有素数了;
            break;
        for(ll j=l/prime[i]*prime[i]; j<=r; j+=prime[i]) //优化 ,每一次都是j+=prime[i];
        {
            if(j>=l)
            {
                int cnt=0;
                while(f[j-l]%prime[i]==0)
                {
                    cnt++;
                    f[j-l]/=prime[i];
                }
                g[j-l]=g[j-l]*(cnt*k+1)%mod;
            }
        }
    }

    for(ll i=l; i<=r; i++)
    {
        if(f[i-l]>1)
            g[i-l]=g[i-l]*(k+1)%mod;
        ans=ans+g[i-l];
        if(ans>=mod)
            ans%=mod;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    get_prime();

    while(T--)
    {
        ans=0;
        scanf("%I64d%I64d%I64d",&l,&r,&k);
        work();
        printf("%I64d\n",ans%mod);
    }
    return 0;
}

代码中有 l / prime[i] * prime[i] ,这个代码是找到离 l 最近的,小于等与 l 的,能够整除 prime[i] 的数;
参考队友的思路,代码,≧ ﹏ ≦
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值