题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6069
参考:
- https://blog.csdn.net/ctsas/article/details/76640313
- https://blog.csdn.net/dDarkdawn/article/details/76775232
题意:首先表示
的约数的个数,每组样例给出
让求:
其中:
解析:首先要知道约数个数定理:
对于一个大于1正整数n可以分解质因数:
则n的正约数的个数就是:
那么,考虑到
,尝试枚举
间的每个数,然后对每个数分解质因子是超时的。转变思路想到枚举
之间的所有素数
,再枚举区间
中所有
的倍数
,对所有
的倍数
累计
对其的贡献,然后将
除以
表示己经算过
的贡献,最后区间中每一个数除完剩下值不为
的部分就是超过枚举的质数的剩余质数,只可能是
个或
个,对于有剩余的再统计一下这个最后的质数的贡献即可。具体看代码吧,代码还是很好理解的。
复杂度。
代码(2355ms):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=1e6+500;
const ll MOD=998244353;
ll len,prime[MAXN+50];
bool vis[MAXN+50];
ll l,r,k;
ll d[MAXN+50],arr[MAXN+50];
void init()
{
ll tmp;
int i,j;len=0;
for(i=2;i<MAXN;i++)
{
if(!vis[i])
prime[len++]=i;
for(j=0;j<len;j++)
{
tmp=i*prime[j];
if(tmp>MAXN) break;
vis[tmp]=true;
if(i%prime[j]==0)
break;
}
}
}
ll work(ll l,ll r,ll k)
{
for(ll i=l;i<=r;i++)//d[i-l]统计区间中i的答案,arr[i-l]是它的本身数值
{
d[i-l]=1;
arr[i-l]=i;
}
for(ll i=0;i<len;i++)//枚举每一个素数
{
ll pos=(l/prime[i])*prime[i]+(l%prime[i]!=0)*prime[i];//pos是素数prime[i]区间中的第一个倍数
while(pos<=r)//pos枚举每个倍数
{
ll cnt=0;
while(arr[pos-l]%prime[i]==0)//prime[i]对pos的答案的贡献为cnt*k+1
{
cnt++;
arr[pos-l]=arr[pos-l]/prime[i];
}
d[pos-l]=d[pos-l]*(cnt*k+1)%MOD;
pos+=prime[i];
}
}
ll ans=0;
for(ll i=l;i<=r;i++)
{
if(arr[i-l]==1)//没有剩余素数
ans=(ans+d[i-l])%MOD;
else {
ans=(ans+d[i-l]*(k+1))%MOD;
}
}
return ans;
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&l,&r,&k);
printf("%lld\n",work(l,r,k));
}
return 0;
}