1. 程式人生 > >Hdu 6069 Counting Divisors【素數區間篩+預處理素因子分解】

Hdu 6069 Counting Divisors【素數區間篩+預處理素因子分解】

Counting Divisors

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 3150    Accepted Submission(s): 1175


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(1T15), denoting the number of test cases.

In each test case, there are 3 integers l,r,k(1lr1012,rl10
6
,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

題目大意:

設定D(i)表示詢問數字i有多少個因子。

讓我們求區間【L,R】內,D(i^k)的和。

思路:

我們知道,求D(i)可以將數字i進行素因子分解,我們有:i=p1^ans1+p2^ans2+p3^ans3+p4^ans4+...........計算D(i)=(ans1+1)*(ans2+1)*(ans3+1)*.................

我們現在要求D(i^k)的話,結果是等比例增長的,那麼D(i^k)=(ans1*k+1)*(ans2*k+1)*(ans3*k+1)*.................

迴歸問題,觀察到R-L<=1e6的,那麼我們根據熟知的理論,我們將根號R以內的素數預處理出來,然後預處理篩法處理出所有數字的素因子分解的情況即可。

值得注意的一點是,預處理區間素數和區間內素因子分解的結果之後,我們可能有紕漏,也就是會有數字num,不斷除素因子之後 ,可能最終剩下的數不是1.可能是一個大於根號R的素數,那麼在記錄答案的時候統計起來即可。

Ac程式碼:

#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long int
#define Maxn 1005000
int tot;
int Is_or[1105000];
ll prime[1105000];
ll ans[1105000];
ll num[1105000];
ll mod=998244353;
void init()
{
    tot=0;
    memset(prime,0,sizeof(prime));
    memset(Is_or,0,sizeof(Is_or));
    for(int i=2;i<=Maxn;i++)
    {
        if(Is_or[i]==0)
        {
            prime[tot++]=i;
            for(int j=i*2;j<=Maxn;j+=i)
            {
                Is_or[j]=1;
            }
        }
    }
}
void Div(ll L,ll R,ll k)
{
    for(int i=0;i<=R-L;i++)
    {
        ans[i]=1;
        num[i]=i+L;
    }
    for(ll i=0;i<tot;i++)
    {
        ll b=L/prime[i];
        while(b*prime[i]<L||b<=1)b++;
        for(ll j=b*prime[i];j<=R;j+=prime[i])
        {
            ll cnt=0;
            while(num[j-L]%prime[i]==0)cnt++,num[j-L]/=prime[i];
            ans[j-L]*=(cnt*k+1);
            ans[j-L]%=mod;
        }
    }
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll l,r,k;
        scanf("%lld%lld%lld",&l,&r,&k);
        Div(l,r,k);
        ll output=0;
        for(ll i=0;i<=r-l;i++)
        {
            if(num[i]!=1)output+=ans[i]*(k+1);
            else output+=ans[i];
            output%=mod;
        }
        printf("%lld\n",output);
    }
}