P3312 数表
题意
求出
[sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j))[sigma(gcd(i,j))le a]
]
其中 (sigma) 表示约数和。
思路/推导
考虑没有 (a) 的限制的情况。
[egin{aligned}
ans&=sum_{d=1}^{min(n,m)}sigma(d)sum_{i=1}^{leftlfloorfrac{n}{d}
ight
floor}sum_{j=1}^{leftlfloorfrac{m}{d}
ight
floor}[gcd(i,j)=1]\
&=sum_{d=1}^{min(n,m)}sigma(d)sum_{i=1}^{leftlfloorfrac{n}{d}
ight
floor}sum_{j=1}^{leftlfloorfrac{m}{d}
ight
floor}sum_{pmid iland pmid j}mu(p)\
&=sum_{d=1}^{min(n,m)}sigma(d)sum_{p=1}^{leftlfloorfrac{min(n,m)}{d}
ight
floor}mu(p)leftlfloorfrac{n}{dp}
ight
floorleftlfloorfrac{m}{dp}
ight
floor\
&=sum_{T=1}^{min(n,m)}sum_{d=1}^Tsigma(d)mu(frac Td)leftlfloorfrac{n}{T}
ight
floorleftlfloorfrac{m}{T}
ight
floor
end{aligned}
]
考虑加入 (a) 的限制。将询问按照 (a) 大小离线,然后用一个树状数组维护 (sum_dsigma(d)mu(frac Td)) 的前缀和即可。
具体是将线性筛出的所有数的约数和从小到大进行排序,在从小到大查询的时候进行更新。
不会筛 (sigma) 的可以看我的另一篇博客
时间复杂度瓶颈在于查询,需要用到数论分块,为 (O(qsqrt nlog n))。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#include<utility>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=1e5+10,maxm=2e4+10,N=1e5;
int n,p[maxn/10],mu[maxn],tot,c[maxn],ans[maxm],g[maxn];
pair<int,int> f[maxn];
bool mark[maxn];
inline void insert(int x,int k){for(;x<=N;x+=x&-x) c[x]+=k;}
inline int query(int x){int ans=0;for(;x;x-=x&-x) ans+=c[x];return ans;}
struct Query{
int n,m,a,id;
inline bool operator < (const Query& zp) const {return a<zp.a;}
inline int solve(){
if(n>m) swap(n,m);
int ans=0;
for(int l=1,r;l<=n;l=r+1)
r=min(n/(n/l),m/(m/l)),ans+=((query(r)-query(l-1))*(n/l)*(m/l));
return ans;
}
}q[maxm];
inline void work(){
mu[1]=1;
f[1]=make_pair(1,1);
for(int i=2;i<=N;i++){
if(!mark[i]) p[++tot]=i,mu[i]=-1,g[i]=i+1,f[i]=make_pair(i+1,i);
for(int j=1,tmp;j<=tot and (tmp=i*p[j])<=N;j++){
mark[tmp]=true;
if(i%p[j]==0){
mu[tmp]=0;
g[tmp]=g[i]*p[j]+1;
f[tmp]=make_pair(f[i].first/g[i]*g[tmp],tmp);
break;
}
mu[tmp]=-mu[i];
g[tmp]=p[j]+1;
f[tmp]=make_pair(f[i].first*f[p[j]].first,tmp);
}
}
sort(f+1,f+1+N);
n=read();
for(int i=1;i<=n;i++) q[i].n=read(),q[i].m=read(),q[i].a=read(),q[i].id=i;
sort(q+1,q+1+n);
for(int i=1,j=1;i<=n;i++){
while(f[j].first<=q[i].a and j<=N){
for(int k=f[j].second;k<=N;k+=f[j].second) insert(k,f[j].first*mu[k/f[j].second]);
j++;
}
ans[q[i].id]=q[i].solve();
}
for(int i=1;i<=n;i++) printf("%d
",ans[i]&(~(1<<31)));
}
}
signed main(){
star::work();
return 0;
}