正题
题目链接:https://www.luogu.com.cn/problem/P3312
题目大意
定义F(x)F(x)F(x)表示xxx的约数和
给出n,m,an,m,an,m,a,求∑i=1n∑j=1m[F(gcd(i,j))≤a]∗F(gcd(i,j))\sum_{i=1}^n\sum_{j=1}^m[F(gcd(i,j))\leq a]*F(gcd(i,j))i=1∑nj=1∑m[F(gcd(i,j))≤a]∗F(gcd(i,j))
解题思路
首先我们不考虑aaa的限制,我们定义g(i)=∑i∣dμ(id)⌊ni⌋⌊mi⌋g(i)=\sum_{i|d}\mu(\frac{i}{d})\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloorg(i)=∑i∣dμ(di)⌊in⌋⌊im⌋。那么我们有ans=∑i=1nF(i)g(i)=∑i=1nF(i)∑i∣dμ(id)⌊ni⌋⌊mi⌋ans=\sum_{i=1}^nF(i)g(i)=\sum_{i=1}^nF(i)\sum_{i|d}\mu(\frac{i}{d})\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloorans=i=1∑nF(i)g(i)=i=1∑nF(i)i∣d∑μ(di)⌊in⌋⌊im⌋
⇒ans=∑d=1n⌊ni⌋⌊mi⌋∑i∣dF(i)μ(di)\Rightarrow ans=\sum_{d=1}^n\lfloor \frac{n}{i}\rfloor\lfloor \frac{m}{i}\rfloor\sum_{i|d}F(i)\mu(\frac{d}{i})⇒ans=d=1∑n⌊in⌋⌊im⌋i∣d∑F(i)μ(id)
显然我们可以计算∑i∣dF(i)μ(di)\sum_{i|d}F(i)\mu(\frac{d}{i})∑i∣dF(i)μ(id)的前缀和来统计
考虑aaa的限制,我们发现对于F(i)>aF(i)>aF(i)>a那么有F(i)=0F(i)=0F(i)=0。我们可以将询问的aaa从小到大排序,然后按照F(i)μ(di)F(i)\mu(\frac{d}{i})F(i)μ(id)从小到大的顺序插入,因为要求前缀和,所以在树状数组里插入即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e5+10;
int T,n[N],m[N],a[N],p[N],t[N],nm;
int mu[N],f[N],g[N],pri[N],q[N],ans[N];
bool vis[N];
void prime(){int cnt=0;mu[1]=f[1]=1;for(int i=2;i<=nm;i++){if(!vis[i])vis[i]=1,pri[++cnt]=i,f[i]=g[i]=i+1,mu[i]=-1;for(int j=1;j<=cnt&&pri[j]*i<=nm;j++){vis[pri[j]*i]=1;if(i%pri[j]==0){mu[i*pri[j]]=0;g[i*pri[j]]=g[i]*pri[j]+1;f[i*pri[j]]=f[i]/g[i]*g[i*pri[j]];break;}mu[i*pri[j]]=-mu[i];f[i*pri[j]]=f[i]*f[pri[j]];g[i*pri[j]]=pri[j]+1;}}for(int i=1;i<=nm;i++)q[i]=i;
}
void Change(int x,int val){while(x<=nm){t[x]+=val;x+=lowbit(x);}return;
}
int Ask(int x){int ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
bool cmp(int x,int y)
{return a[x]<a[y];}
bool cMp(int x,int y)
{return f[x]<f[y];}
int main()
{scanf("%d",&T);for(int i=1;i<=T;i++){scanf("%d%d%d",&n[i],&m[i],&a[i]);p[i]=i;}nm=100000;prime();sort(p+1,p+1+T,cmp);sort(q+1,q+1+nm,cMp);int jz=1;for(int i=1;i<=T;i++){int x=p[i];while(jz<=nm&&f[q[jz]]<=a[x]){for(int j=q[jz];j<=nm;j+=q[jz])Change(j,f[q[jz]]*mu[j/q[jz]]);jz++;}if(n[x]>m[x])swap(n[x],m[x]);for(int l=1,r;l<=n[x];l=r+1){r=min(n[x]/(n[x]/l),m[x]/(m[x]/l));ans[x]+=(n[x]/l)*(m[x]/l)*(Ask(r)-Ask(l-1));}}for(int i=1;i<=T;i++)printf("%d\n",ans[i]&(~(1<<31)));
}