【bzoj3529】数表

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 }
posted @ 2018-08-22 21:58  乖巧的小团子QwQ  阅读(195)  评论(0编辑  收藏  举报