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 :
( ∑ri=ld(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
Source
2017 Multi-University Training Contest - Team 4
题意:
给定l,r,k,求 ik 的因子个数之和。(l<i<r)
想法:
首先,有这么你不知道就做不出来这道题的定理:)
约数个数定理:
对于一个大于1正整数n可以分解质因数,
如果它的标准分解式为:N=P
a11
P
a22
……P
ann
,
那么它的正因数个数为f(N)=(1+
a1
)·(1+
a2
)·⋯·(1+
an
),
所以f(
Nk
)=(1+
ka1
)·(1+
ka2
)·⋯·(1+
kan
)
我们只要想办法把每个数分解成质因数再运用定理公式累加即可。
但是单独的把一个数直接分很困难,所以我们来枚举(l,r)内小于
r√的
素数,来判断这个素数(包括其倍数)是不是这个数的素因子。若是就进入约数个数定理的函数,不是就不进入呗~
tips:
1.选出这些素数运用的是素数筛。
2.注意题目要求 不断取余。
3.约数个数定理中注意i的初始化,以及走完这个函数后,最后还要处理一下仍未被分解完成的数。
#include<cstdio>
using namespace std;
const int mod=998244353;
const int maxn=1e6+10;
typedef long long ll;
ll f[maxn],g[maxn],su[maxn/10];//f[i]表示每个区间内的底数 g[i]是每个指数的因子个数 su[i]表示每个素因子
ll cnt,l,r,k;
bool vis[maxn];
void solve(ll p)//约数个数定理 每次传入一个素数 判断这个数是不是这个数的素因子
{
for(ll i=l/p*p;i<=r;i+=p)//注意i的初始化 i是指区间第几个数
{///这里令i先除以p,再乘以p,就可以在小于等于L的区间里找到第一个能被p整除的数(重点)。
if(i>=l)
{
int mi=0;///表示p的指数
while(f[i-l]%p==0)
{
f[i-l]/=p;
mi++;
}
g[i-l]=1LL*g[i-l]*(1+mi*k)%mod;//这里因为忘了取余错了QAQ
}
}
}
int main()
{
cnt=0;
for(ll i=2;i<maxn;++i)//素数筛
{
if(!vis[i])
su[cnt++]=i;//cnt是素数个数
for(ll j=0;j<cnt&&i*su[j]<maxn;j++)
{
vis[i*su[j]]=1;
if(i%su[j]==0)
break;
}
}
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&l,&r,&k);
int n=r-l+1;//区间内总个数
for(int i=0;i<n;++i)
{
f[i]=l+i;///f[i]表示从左往右第i个底数
g[i]=1;
}
for(int i=0;i<cnt;++i)
{
if(1LL*su[i]*su[i]>r)//若质数平方大于右边界 直接跳出
{
break;
}
solve(su[i]);
}
ll ans=0;
for(int i=0;i<n;++i)
{///在都进入过约数个数定理函数分解后
if(f[i]>1)///讨论没有被质数除尽的,和本身是大于根号r的大素数
{
g[i]=1LL*(1+k)*g[i]%mod;
}
ans=(ans+g[i])%mod;
}
printf("%d\n",ans);
}
return 0;
}
ps:会了定理就会了 可是我不知道定理(手动微笑)