Description
给定n,m,a(n,m<=107,a<=109),求$\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}f(gcd(i,j))[f(gcd(i,j))<=a]$(多组数据,q<=200000),其中,f(n)表示n的约数和。
Solution
我们忽略$f(gcd(i,j))<=a$,可得
$ans=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}f(gcd(i,j))$
$=\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}[gcd(i,j)=1]$
$=\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}\sum\limits_{p|i,p|j}μ(p)$
$=\sum\limits_{d=1}^{n}f(d)\sum\limits_{p=1}^{\left\lfloor\frac{n}{d}\right\rfloor}μ(p)\left\lfloor\frac{n}{pd}\right\rfloor\left\lfloor\frac{m}{pd}\right\rfloor$
记$t=pd$,则
$ans=\sum\limits_{t=1}^{n}\left\lfloor\frac{n}{t}\right\rfloor\left\lfloor\frac{m}{t}\right\rfloor\sum\limits_{d|t}f(d)μ(\frac{t}{d})$
现在看$f(gcd(i,j))<=a$这一限制条件,我们用线性筛预处理出$\sum\limits_{d|t}f(d)μ(\frac{t}{d})$的前缀和后,离线处理询问,将询问按a的大小从小往大排,每次处理询问将符合条件的f值加入树状数组,然后按照$\left\lfloor\frac{n}{t}\right\rfloor$的值分块处理就可以啦,时间复杂度$O(q\sqrt{n})$。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100000; 6 const int Q=20000; 7 struct node{ 8 int val,id; 9 }a[N+10]={0}; 10 struct ques{ 11 int n,m,a,id; 12 }f[Q+10]={0}; 13 int q,p[N+10]={0},miu[N+10]={0},t[N+10]={0},s[N+10]={0}; 14 int ans[Q+10]={0}; 15 bool check[N+10]={false}; 16 bool cmp1(node a,node b){ 17 return a.val<b.val; 18 } 19 bool cmp2(ques a,ques b){ 20 return a.a<b.a; 21 } 22 void get_miu(){ 23 miu[1]=a[1].val=1; 24 for(int i=2;i<=N;i++){ 25 if(!check[i]){ 26 miu[p[++p[0]]=i]=-1; 27 a[i].val=t[i]=i+1; 28 } 29 for(int j=1;i*p[j]<=N&&j<=p[0];j++){ 30 check[i*p[j]]=true; 31 if(i%p[j]){ 32 miu[i*p[j]]=-miu[i]; 33 t[i*p[j]]=p[j]+1; 34 a[i*p[j]].val=a[i].val*t[i*p[j]]; 35 } 36 else{ 37 t[i*p[j]]=t[i]*p[j]+1; 38 a[i*p[j]].val=a[i].val/t[i]*t[i*p[j]]; 39 break; 40 } 41 } 42 } 43 for(int i=1;i<=N;i++) 44 a[i].id=i; 45 sort(a+1,a+N+1,cmp1); 46 return; 47 } 48 void update(int x,int k){ 49 for(;x<=N;x+=x&-x) 50 s[x]+=k; 51 return; 52 } 53 int query(int x){ 54 int ret=0; 55 for(;x;x-=x&-x) 56 ret+=s[x]; 57 return ret; 58 } 59 int solve(int n,int m){ 60 int ret=0; 61 if(n>m) 62 swap(n,m); 63 for(int i=1,j;i<=n;i=j+1) 64 ret+=(query(j=min(n/(n/i),m/(m/i)))-query(i-1))*(n/i)*(m/i); 65 return ret&0x7fffffff; 66 } 67 int main(){ 68 get_miu(); 69 scanf("%d",&q); 70 for(int i=1;i<=q;i++){ 71 scanf("%d%d%d",&f[i].n,&f[i].m,&f[i].a); 72 f[i].id=i; 73 } 74 sort(f+1,f+q+1,cmp2); 75 a[N+1].val=0x3f3f3f3f; 76 for(int i=1,j=1;i<=q;i++){ 77 for(;a[j].val<=f[i].a;j++) 78 for(int k=a[j].id;k<=N;k+=a[j].id) 79 update(k,a[j].val*miu[k/a[j].id]); 80 ans[f[i].id]=solve(f[i].n,f[i].m); 81 } 82 for(int i=1;i<=q;i++) 83 printf("%d\n",ans[i]); 84 return 0; 85 }