天天看點

17暑假多校聯賽4.3 HDU 6069 Counting Divisors

Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)

Memory Limit: 524288/524288 K (Java/Others)

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 :

(∑i=lrd(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(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
           

題目網址:http://acm.hdu.edu.cn/showproblem.php?pid=6069

分析

題意:

T

組測試資料,每組給出

l,r,k

,計算

l

r

每個數

k

次方的因子個數,并求和

可以推出規律:質數的

k

次方的因子個數為

k+1

比如求整數

a

k

次方的因子個數:

如果

a=6,k=2

,則

36

的因子有

1,2,3,4,6,9,12,18,36

總共

9

如果将

6

分解質因子,

6=2*3

2,3

都是質數,是以

6

的平方的因子數為

(k+1)*(k+1)

,即

3*3=9

可以得出規律:如果

a

分解質因子為

a=p[1]^x*p[2]^y*p[3]^z

(其中

p[1],p[2],p[3]

均為素數),則

a

k

次方的因子個數為:

(x*k+1)*(y*k+1)*(z*k+1)

a

k

次方分解質因子為

a^k=p[1]^(x*k)*p[2]^(y*k)*p[3]^(z*k)

是以可以将

l

r

每個數分解質因子,并記錄每個質因子出現的次數,然後根據上面的規律計算出每個數

k

次方的因子個數,求和即可

由于數值比較大,這道題很容易時間超限,是以要注意求解的方法,還要不斷取模

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
using namespace std;
const int maxn=+;
const int mod=;
int tot,t;
ll l,r,k,ans,cnt[maxn],q[maxn],primes[maxn];
///cnt存放d(i^k)的值,q存放區間每個對應位置的數值
bool vis[maxn];
void init()///素數打表
{
    for(int i=; i<maxn; i++)
    {
        if(!vis[i])///如果沒有被标記就存入素數數組
            primes[tot++]=i;
        for(int j=; j<tot; j++)///将素數i和他的倍數都标記
        {
            int k=i*primes[j];
            if(k>maxn)break;
            vis[k]=;
        }
    }
}
int main()
{
    scanf("%d",&t);
    init();
    while(t--)
    {
        scanf("%lld%lld%lld",&l,&r,&k);
        ans=;
        if(l==) ans++,l++;
        ///1的多少次幂都是1,d(1)等于1
        ///是以如果左邊界是1,直接将ans加1,把左邊界移到2
        for(ll i=; i<=r-l; i++) cnt[i]=,q[i]=l+i;
        ///将l到r對應位置的數值存入q,給cnt數組賦初值為1
        for(ll i=; primes[i]*primes[i]<=r; i++)
        {
            ll j=l/primes[i]+(l%primes[i]!=);
            ///i和j來控制primes[i]*j在給定區間内
            for( j=j*primes[i]; j<=r; j+=primes[i])
            {
                ll tmp=;
                while(q[j-l]%primes[i]==) q[j-l]/=primes[i],tmp++;
                ///計算q[j-l]的因數中包含多少個primes[i],存到tmp中
                (cnt[j-l]*=(tmp*k)%mod+)%=mod;
                ///将因子數存入cnt[j-l]
            }
        }
        for(ll i=; i<=r-l; i++)
        {
            if(q[i]!=) ans+=((k+)*cnt[i])%mod;
            ///q[i]不為1,說明q[i]的初值是l到r内的素數或其倍數
            ///由于前面已經控制了primes[i]*primes[i]<=r
            ///是以倍數在前邊已經計算出了并将其因子數存給了cnt[i]
            ///是以,隻用乘上k+1即可
            else ans+=cnt[i];
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
}