P4240 毒瘤之神的考验
ANIG 不知道为啥突然做这题,【数据删除】。
description
\(Q\) 次询问,每次给定 \(n,m\),求 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^m \varphi(ij)\)
-
\(Q\leq 10^4\)
-
\(n,m\leq 10^5\)
solution
一种不太要动脑子的做法。
先套路地推式子,发现原式等于 \(\sum\limits_{T=1}^{\min(n,m)} S(T,n)S(T,m)\sum\limits_{d\mid T} \dfrac{d}{\varphi(d)}\mu(\dfrac{T}{d})\),其中 \(S(a,b)=\sum\limits_{i=1}^b [a\mid i]\varphi(i)\)。
设 L 为值域,对每个数 \(p\) 处理出来 \(\lfloor\dfrac{L}{p}\rfloor\) 个位置 \(x\) 的 \(\varphi(p\times x)\) 的前缀和,这样就可以 \(O(1)\) 回答 \(S(a,b)\)。预处理的位置个数是 \(O(n\ln n)\) 的。
后面的 \(\sum\limits_{d\mid T} \dfrac{d}{\varphi(d)}\mu(\dfrac{T}{d})\) 可以预处理。
注意到对于所有 \(T\),\(S(T,n)\to S(T,n+1)\) 时,只有 \(n+1\) 的约数处的 \(T\) 的函数值会发生变化,因此我们可以 \(O(d(n+1))\) 地把答案从 \((n,m)\) 处的转移到 \((n+1,m)\) 处的。
把所有询问离线,使用莫队,设块长为 \(W\),每块内因数个数最多的数的因数个数平均是 \(d\),即可做到 \(O(\dfrac{L}{W}\times L\times \log L+Q\times W\times d)\)。实际上 \(d\) 大概和 \(\log L\) 相当。
故取 \(W=\dfrac{L}{\sqrt{Q}}\) 有最优复杂度 \(O(L\sqrt{Q}\log L)\)。
code
#include<bits/stdc++.h>
using namespace std;
using E=long long;
constexpr E mod=998244353;
E T=1e5;
vector<E> phi,miu,f,primes,st;
E ksm(E a,E b){
E ret=1;
while(b){
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
int main(){
cout.tie(nullptr),cin.tie(nullptr)->sync_with_stdio(false);
phi=miu=f=st=vector<E>(T+1);
phi[1]=miu[1]=1;
for(int i=2; i<=T; i++){
if(!st[i]){
primes.emplace_back(i);
phi[i]=i-1;
miu[i]=-1;
}
for(auto j:primes){
if(i*j>T) break;
st[i*j]=1;
if(i%j==0){
miu[i*j]=0;
phi[i*j]=phi[i]*j;
break;
}
phi[i*j]=phi[i]*phi[j];
miu[i*j]=miu[i]*miu[j];
}
}
for(int i=1; i<=T; i++) miu[i]=(miu[i]%mod+mod)%mod;
vector<vector<int>> divis(T+1);
vector<vector<E>> sum(T+1);
for(int i=1; i<=T; i++){
E coef=i*ksm(phi[i],mod-2)%mod;
for(int j=i; j<=T; j+=i){
f[j]=(f[j]+coef*miu[j/i]%mod)%mod;
divis[j].emplace_back(i);
}
}
for(int i=1; i<=T; i++){
sum[i].emplace_back(0);
for(int j=i; j<=T; j+=i){
sum[i].emplace_back(sum[i].back()+phi[j]);
sum[i][sum[i].size()-1]%=mod;
}
}
struct querys{
int l,r;
int idx;
querys(int x=0,int y=0,int z=0){
l=x,r=y,idx=z;
}
};
vector<querys> Q;
int q;
cin>>q;
for(int i=1; i<=q; i++){
int l,r;
cin>>l>>r;
Q.emplace_back(querys(l,r,i));
}
int bksz=450;
sort(Q.begin(),Q.end(),[&](const querys &x,const querys &y)->bool{
if((x.l/bksz)==(y.l)/bksz){
return (bool)(((x.l/bksz)&1)^(x.r<y.r));
}
return x.l<y.l;
});
int l,r;
E ans=0;
l=r=ans=1;
auto add=[&](int m,int pos,int op)->void{
E x=0;
for(auto p:divis[pos]){
x=(x+phi[pos]*(sum[p][m/p])%mod*f[p])%mod;
}
x=x*op%mod;
ans=(ans+x)%mod;
};
vector<E> res(q+1);
for(int tt=0; tt<q; tt++){
int L=Q[tt].l,R=Q[tt].r;
while(l<L){
add(r,l+1,1);
l++;
}
while(l>L){
add(r,l,mod-1);
l--;
}
while(r<R){
add(l,r+1,1);
r++;
}
while(r>R){
add(l,r,mod-1);
r--;
}
res[Q[tt].idx]=ans;
}
for(int i=1; i<=q; i++) cout<<res[i]<<'\n';
return 0;
}

浙公网安备 33010602011771号