先打表筛选1~1e6内的素数,L,R最多到1e12,然后一个数是素数是这样定义的,如果n是素数,则2~(int)sqrt(n),都不能被n整除。
所以我们筛选素数只需要筛选到sqrt(1e12)范围就好。
其次,任何一个正整数x,都可以分解成若干个素数幂的积。小学学的分解质因子的方法就是这样的。
则 x = (p1^m1)*(p2^m2)*(p3^m3)*.....*(pn^mn); 其中p1,p2,p3...pn都是素数,m1,m2,m3...mn都是幂指数。
则 x 的因子个数d(x) = (m1+1)*(m2+1)*(m3+1)....(mn+1);
这和这些素因子的排列组合有关,举个例子:
例如 12 = 2×2×3
则 12的因子个数为 1 ×(2+1)×(1+1) = 3*2 = 6
12的因子有: 1 2 3 4 6 12 可以看出答案是正确的。那么为什么会是这样的。
这主要是和这些质因子的组合有关。12 由两个2,和一个3连乘得到
则组合情况有:0个2和0个3乘 1
1个2和0个3乘 2
2个2和0个3乘 4
0个2和1个3乘 3
1个2和1个3乘 6
2个2和1个3乘 12
对于x^k = ((p1^m1)*(p2^m2)*(p3^m3)*.....*(pn^mn))^k;
x^k = (p1^m1*k)*(p2^m2*k)*(p3^m3*k)*.....*(pn^mn*k);
则x^k的因子个数d(x^k) = (m1*k+1)*(m2*k+1)*(m3*k+1)*.....*(mn*k+1);
因为读过《基础数论》这本书,这些结论都知道,就是比赛的时候,求完素数表示,一直都时对每一个数进行分解质因数,
最后导致一直超时,方法不合适,怎么改最后都超时,比赛后看他们都是对某个素数,直接将其倍数直接筛过,这样的确快很多,
只怪自己太笨,不懂得变通,又签到了一场比赛。
AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
const int maxn = 1000100;
int prime[maxn]; ///素数表
LL a[maxn];
LL yinzi[maxn];
int num;
void create_table()
{
memset(a,0,sizeof(a)); ///0代表是素数
for(int i = 2; i <= sqrt(maxn); i++)
{
for(int j = 2*i; j <= maxn; j+=i)
{
if(a[j]==0)
a[j] = 1;
}
}
num = 0;
for(int i = 2; i <= maxn; i++)
{
if(a[i]==0)
{
prime[num++] = i;
}
}
}
/**由于left和right值比较大,所以存他们的
相关信息存不下,而left和right差距不超过1e6,
因此hash一下,将其散列到0~1e6内**/
void Hash(LL left,LL right)
{
///
for(LL i = left; i <= right; i++)
{
yinzi[i-left] = 1;
a[i-left] = i;
}
}
void solve(LL left,LL right,int k)
{
for(int i = 0; i<num && prime[i]<=sqrt(right*1.0); i++)
{
LL start,ccount;
if(left%prime[i]==0) start = left;
else start = left/prime[i]*prime[i]+prime[i]; ///求起点
for(LL j = start; j <= right; j += prime[i])
{
ccount = 0; ///记录prime[i]的幂
while(a[j-left]%prime[i]==0)
{
ccount++;
a[j-left] = a[j-left]/prime[i];
}
yinzi[j-left] = ((yinzi[j-left]%mod)*((ccount*k+1)%mod))%mod;
}
}
LL ans = 0;
for(int i = 0; i <= right-left; i++)
{
if(a[i]!=1) ///代表是素数
{
ans = (ans+(yinzi[i]*(k+1))%mod)%mod;
}
else
{
ans = (ans+yinzi[i])%mod;
}
}
cout<<ans<<endl;
}
int main()
{
int t,k;
LL left,right;
create_table(); ///打素数表
cin>>t;
while(t--)
{
cin>>left>>right>>k;
Hash(left,right);
solve(left,right,k);
}
return 0;
}