设
x
=
p
1
a
1
p
2
a
2
.
.
.
.
p
n
a
n
x = p_1^{a_1}p_2^{a_2}....p_n^{a_n}
x=p1a1p2a2....pnan
则
d
(
x
)
=
(
1
+
a
1
)
(
1
+
a
2
)
.
.
.
(
1
+
a
n
)
d(x) = (1+a_1)(1+a_2)...(1+a_n)
d(x)=(1+a1)(1+a2)...(1+an)
d
(
x
k
)
=
(
1
+
k
a
1
)
(
1
+
k
a
2
)
(
1
+
k
a
3
)
.
.
.
(
1
+
k
a
n
)
d(x^k) = (1+ka_1)(1+ka_2)(1+ka_3)...(1+ka_n)
d(xk)=(1+ka1)(1+ka2)(1+ka3)...(1+kan)
因 k k k已知,所以我们只需要知道 L < = x < = R L<=x<=R L<=x<=R的每一个x质因数分解后的 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an便可以求解出答案。
因 x < = 1 e 12 x<=1e12 x<=1e12,故可以考虑枚举出 1 e 6 1e6 1e6以内的素数,采用区间素数筛求出每一个数的质因数指数。(可参考白书(《挑战程序设计竞赛》)素数一章的例题)
设区间长度为
n
n
n
总复杂度
O
(
R
+
n
l
o
g
l
o
g
n
)
O(\sqrt R+nloglog n)
O(R+nloglogn)
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int P = 998244353;
const int G = 3;
const int A = 1e6 + 10;
const int N = 70;
bool vis[A];
int pri[A],tot;
void init(){
tot = 0;
for(ll i=2 ;i<A ;i++){
if(!vis[i]){pri[++tot] = i;}
for(ll j=1 ;j<=tot && i*pri[j]<A ;j++){
vis[i*pri[j]] = 1;
if(i%pri[j] == 0) break;
}
}
}
ll ans[A],val[A];
void solve(ll L,ll R,ll t){
for(ll i=L ;i<=R ;i++){
ans[i-L] = 1;
val[i-L] = i;
}
for(ll i=1 ;i<=tot ;i++){
ll now = pri[i];
for(ll j=max(2LL,(L+now-1)/now)*now ;j<=R ;j+=now){
if(val[j-L] % now) continue;
ll cnt = 0;
while(val[j-L] % now == 0){val[j-L]/=now;cnt++;}
ans[j-L] = (1+t*cnt)%P*ans[j-L]%P;
}
}
for(ll i=L ;i<=R ;i++){
if(val[i-L] > 1){
ans[i-L] = (1+t)%P*ans[i-L]%P;
}
}
ll sum = 0;
for(ll i=L ;i<=R ;i++){
sum = (sum + ans[i-L]) % P;
}
printf("%I64d\n",sum);
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
ll l,r,k;
scanf("%I64d%I64d%I64d",&l,&r,&k);
solve(l,r,k);
}
return 0;
}
反思:非常简单的一题。本来我队开场三十分钟就推出了该公式并在白书上找到了区间筛的原题和代码。按正常剧情本应该是最多一小时内就能正确AC此题,但作为队内此题的负责人,却终场也没有搞出来qwq
问题主要出在两个方面。
一是对自己的第一直觉太自信,赛前两天才开始学FFT和NTT,一看到取模的质数是一个费马质数,存在原根,虽然NTT学得并不好,但仍然固执地认定此题一定需要用到NTT进行优化,并带偏了队友的思路,在没有跟队友讨论确定思路(因对需要使用NTT太自信,而两位队友都没学过该算法,故错误地认为没有讨论的必要)的情况下直接开写,用NTT将
d
(
i
k
)
=
(
1
+
k
a
1
)
(
1
+
k
a
2
)
(
1
+
k
a
3
)
.
.
.
(
1
+
k
a
n
)
d(i^k) = (1+ka_1)(1+ka_2)(1+ka_3)...(1+ka_n)
d(ik)=(1+ka1)(1+ka2)(1+ka3)...(1+kan)
关于k的多项式进行展开运算,从而引起时间复杂度爆炸,提交的代码T了很多次,浪费了大量时间。
另外一方面便在于对算法时间复杂度的估算不够重视。本来半小时想出的思路是可以正确AC的,却凭自我感觉认为其复杂度太高(因结果表达式太直接地就推了出来),跳过了复杂度估算的步骤,一直错误地思考着优化式子的办法,并强行用上了NTT(果然还是太弱了qwq