題意
設d(n)爲n的因子的個數,讓你求
題解
這題主要用到了一些定理和歐拉篩法。
首先我們應該思考對於d(n)怎麼能簡單計算出來。
這裏有一個定理,由唯一分解定理知
這時我們就能簡單的計算出d(n),同理可以推出
現在對於我們的問題就是怎麼快速的將區間[l,r]中的數唯一分解出來,如果直接l-r遍歷分解的話會超時。那麼怎麼快速求呢?
這裏要知道d(n)是一個積性函數,而積性函數有一個性質就是f(a*b)=f(a)*f(b),這裏gcd(a,b)=1即a,b互質。而這裏d(n)中對於每一個因子
最後還有一個問題就是l和r的範圍爲
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 1e6+5;
const int mod = 998244353;
//num爲10^6以內素數的個數,prime[]儲存這些素數
ll l,r,k,prime[maxn],num,sz[maxn],res[maxn];
bool isprime[maxn];
void get_Prime() //歐拉篩法
{
num = 0;
memset(isprime,true,sizeof(isprime));
for(int i=2;i<maxn;i++)
{
if(isprime[i]) prime[num++] = i;
for(int j=0;j<num&&prime[j]*i<maxn;j++)
{
isprime[i*prime[j]] = false;
if(i%prime[j]==0) break;
}
}
}
int main()
{
int t;
get_Prime();
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&l,&r,&k);
for(ll i=l;i<=r;i++)
{
sz[i-l] = i;//儲存分解的數
res[i-l] = 1;//儲存區間中數的d()值
}
//對於每個素數對區間開始分解
for(int i=0;i<num&&prime[i]*prime[i]<=r;i++)
{
//從區間中該素數的最小倍數開始分解
for(ll j=prime[i]*(l/prime[i]);j<=r;j+=prime[i])
{
if(j<l) continue;
ll cnt=0;
while(sz[j-l]%prime[i]==0)
{
cnt++;
sz[j-l]/=prime[i];
}
res[j-l] = (res[j-l]*(cnt*k+1))%mod;
}
}
ll ans=0;
for(ll i=l;i<=r;i++)
{
//如果分解剩下的數大於1那麼就一定是一個大於10^6的素數
if(sz[i-l]>1) res[i-l] = (res[i-l]*(k+1))%mod;
ans = (ans+res[i-l])%mod;
}
printf("%lld\n",ans);
}
return 0;
}