题意
给你多组询问,求:
i=1∑nj=1∑mφ(i)φ(j)σ(ij)
其中
1≤T,n,m≤105。
分析
首先我们肯定要把
σ(ij) 拆开。
然后这里有一个结论:
σ(ij)=x∣i∑y∣j∑xiy[gcd(x,y)=1]
该结论的简要证明
感性证明
我们有:
σ(x)=i∏(1+pi+pi2+⋯+piai)每个质因子可以独立处理。
x 和
y 本质上枚举了
i 和
j 的所有质因子组合。
gcd(x,y)=1 保证了每个质因子
x 和
y 中有一个指数为
0。
那么
xiy 就可以取到一个质因子在
ij 中的所有指数。
理性证明
令
vp(n) 表示质因子
p 整除
n 的最高幂次。
由
x∣i,y∣j 易得
0≤vp(x)≤vp(i),0≤vp(y)≤vp(j)。
由
gcd(x,y)=1,易得
min(vp(x),vp(y))=vp(1)=0。
-
当
vp(x)=0 且
vp(y)=0 时,
vp(xiy)=vp(i)+vp(y),恰好取得
[vp(i)+1,vp(i)+vp(j)=vp(ij)] 每个数各一次。
-
当
vp(y)=0 时,
vp(xiy)=vp(i)−vp(x),恰好取得
[0,vp(i)] 每个数各一次。
故
vp(xiy) 不重不漏的取了
[0,vp(ij)] 每个数各一次。
而所有质因子的每种组合都会被取一遍,故结论成立。
最难点已过,恭喜你切掉一道黑题。
接下来就是我们喜闻乐见的推式子时间:
∑i=1n∑j=1mφ(i)φ(j)σ(ij)
用上述结论把
σ(ij) 替掉,得:
∑i=1n∑j=1mφ(i)φ(j)∑x∣i∑y∣jxiy[gcd(x,y)=1]
经典的拆
gcd:
i=1∑nj=1∑mφ(i)φ(j)x∣i∑y∣j∑xiyd∣gcd(x,y)∑μ(d)
d=1∑nμ(d)(d∣x∑nx∣i∑nxiφ(i))(d∣y∑myy∣j∑mφ(j))
令
x=dX,i=xI,y=dY,j=yJ:
d=1∑nμ(d)(X=1∑⌊n/d⌋I=1∑⌊n/dX⌋Iφ(dXI))(Y=1∑⌊m/d⌋dYJ=1∑⌊m/dY⌋φ(dYJ))
把
dY 中的
d 往外提,交换
J,Y 的求和顺序:
d=1∑ndμ(d)(X=1∑⌊n/d⌋I=1∑⌊n/dX⌋Iφ(dXI))(J=1∑⌊m/d⌋Y=1∑⌊m/dJ⌋Yφ(dJY))
注意两个括号是相同的形式,我们令:
F(x,y)=i=1∑xj=1∑⌊x/i⌋jφ(ijy)
F(x,y)=T=1∑xφ(Ty)j∣T∑j=T=1∑xφ(Ty)σ(T)
注意到这东西可以递推:
F(x,y)=F(x−1,y)+φ(xy)σ(x)
将其带入原式,得:
d=1∑ndμ(d)F(⌊dn⌋,d)F(⌊dm⌋,d)
然后就可以用类似
P4240 的方法做了!具体的说:
然后你会发现这个时候
F 里面是带
d 的不能直接的数论分块。我们考虑平衡。
套路地,我们把整个式子换元换出来。我们令:
G(n,m,k)=d=1∑kdμ(d)F(⌊dn⌋,d)F(⌊dm⌋,d)
然后我们发现当
d 很大的时候
⌊dn⌋,⌊dm⌋ 很小,这是不是意味着我们可以预处理一部分
G?
首先我们可以用递推把所有的
F 给预处理出来,时间复杂度是调和级数级别的即
O(nlnn) 的。
设置一个阈值
S,
⌊dn⌋≤S 的部分预处理。用人话说,我们要把
G(x,y,z) 中
x≤S 的所有
G(x,y,z) 的值预处理出来。
因为第三维是可以递推
O(1) 求的,
x 有
S 种取值,
y×z≤m,预处理的时间复杂度是
O(mS) 的。
接下来我们就可以数论分块了,如果预处理过了数论分块算复杂度是
O(Tn) 的,没预处理过暴力算。因为我们已经把
⌊dn⌋≤S 的部分预处理了,所以剩下没预处理的一定满足
d≤⌊S+1n⌋,时间复杂度为
O(SnT)。
总时间复杂度
O(SnT+Tn+mS+nlnn)。反正
n,m 同阶,
S 取
T 可以达到时间复杂度
O((n+m)T+Tn+nlnn)。
代码
代码写的就是一坨大家不要拿我的代码做参考
CPP#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,L=405,TT=998244353;
int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void write(int x){
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);
putchar(x%10+'0');
}
int pri[N],top;
int flg[N];
int mu[N],phi[N];
long long d[N],sp[N];
void init(int n){
mu[1]=1;phi[1]=1;d[1]=1;
for(int i=2;i<=n;i++){
if(!flg[i]){
pri[++top]=i;
phi[i]=i-1;
mu[i]=-1;
d[i]=i+1;
sp[i]=i+1;
}
for(int j=1;j<=top;j++){
int pri_j=pri[j];
if(i*pri_j > n)break;
flg[i*pri_j]=1;
if(i%pri_j==0){
sp[i*pri_j]=sp[i]*pri_j+1;
d[i*pri_j]=d[i]/sp[i]*sp[i*pri_j];
phi[i*pri_j]=phi[i]*pri_j;
mu[i*pri_j]=0;
break;
}
phi[pri_j*i]=phi[i]*phi[pri_j];
d[pri_j*i]=d[pri_j]*d[i];
mu[i*pri_j]=-mu[i];
sp[i*pri_j]=1+pri_j;
}
}
for(int i=1;i<=n;i++)d[i]=d[i]%TT;
}
int T,n,m;
int S;
int f[L][N];
int af[N][505];
void make_f(){
for(int i=1;i<=S;i++){
for(int j=1;i*j<=(N-5);j++){
f[i][j]=((long long)f[i-1][j]+((long long)phi[i*j]*d[i]%TT))%TT;
}
}
for(int j=1;j<=(N-5)/S;j++){
for(int i=1;i*j<=(N-5);i++){
af[i][j]=((long long)af[i-1][j]+((long long)phi[i*j]*d[i]%TT))%TT;
}
}
}
vector<int> g[L][L];
int now;
void make_g(){
for(int i=1;i<=S;i++){
for(int j=1;j<=S;j++){
g[i][j].push_back(0);
for(int k=1;i*k<=(N-5) && j*k<=(N-5);k++){
g[i][j].push_back(((long long)g[i][j][k-1]+(long long)k*(long long)mu[k]%TT*(long long)f[i][k]%TT*f[j][k]%TT+TT)%TT);
}
}
}
}
int calc(int n,int m){
int ret=0,l=1,r=0;
while(l<=n){
r=min(n/(int)(n/l),m/(int)(m/l));
if(r>n)r=n;
if((n/l)<=S && (m/l)<=S){
ret=((long long)ret+(long long)g[n/l][m/l][r]-g[n/l][m/l][l-1]+TT)%TT;
}else{
for(int k=l;k<=r;k++)ret=((long long)ret+(long long)k*(long long)mu[k]%TT*(long long)af[n/l][k]%TT*af[m/l][k]%TT+TT)%TT;
}
l=r+1;
}
return ret;
}
signed main(){
T=read();S=200;
init(N-5);
make_f();make_g();
while(T--){
n=read(),m=read();
if(n>m)swap(n,m);
write(calc(n,m));putchar('\n');
}
return 0;
}
后记
为出题喜欢用经典结论的出题人献上由衷的祝福。
我劝你们家里多备几个【数据删除】。