解题:SDOI 2014 数表

题面 

为了好写式子,先不管$a$的限制

设$facs$为因子和,那么有

$ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^mfacs(gcd(i,j))$

再设$f(k)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)==k]$

熟悉的东西,再写一遍=。=

$f(k)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)==k]$

$=\sum\limits_{i=1}^{min(\left\lfloor\frac{n}{k}\right\rfloor,\left\lfloor\frac{m}{k}\right\rfloor)}μ(i)\left\lfloor\frac{n}{ik}\right\rfloor\left\lfloor\frac{m}{ik}\right\rfloor$

$\sum\limits_{i=1}^{min(n,m)}[k|i]μ(\frac{i}{k})\left\lfloor\frac{n}{i}\right\rfloor\left\lfloor\frac{m}{i}\right\rfloor$

那么

$ans=\sum\limits_{i=1}^{min(n,m)}facs(i)f(i)$

$=\sum\limits_{i=1}^{min(n,m)}facs(i)\sum_{d|i}μ(\frac{i}{d})\left\lfloor\frac{n}{i}\right\rfloor\left\lfloor\frac{m}{i}\right\rfloor$

$=\sum\limits_{i=1}^{min(n,m)}\left\lfloor\frac{n}{i}\right\rfloor\left\lfloor\frac{m}{i}\right\rfloor\sum_{d|i}facs(d)μ(\frac{i}{d})$

预处理后面的那个东西,前面的每次$O(\sqrt n)$回答

等等还有$a$的限制

先读进来按$a$排序,然后依次插入后面那个函数值,也就是单点修改+区间查询,树状数组解决

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=100005,M=1e5,Mod=2147483647;
 6 struct a
 7 {
 8     int n,m,a;
 9     int idx,ans;
10 }qry[N];
11 struct b
12 {
13     int f,idx;
14 }sum[N];
15 int npr[N],pri[N],mul[N],bit[N],T,p,cnt;
16 bool cmp(a x,a y)
17 {
18     return x.a<y.a;
19 }
20 bool com(b x,b y)
21 {
22     return x.f<y.f;
23 }
24 bool cpr(a x,a y)
25 {
26     return x.idx<y.idx;
27 }
28 void Add(int pos,int tsk)
29 {
30     while(pos<=M)
31         bit[pos]+=tsk,pos+=pos&-pos;
32 }
33 int Query(int pos)
34 {
35     int ret=0;
36     while(pos)
37         ret+=bit[pos],pos-=pos&-pos;
38     return ret;
39 }
40 void Prework()
41 {
42     npr[1]=true,mul[1]=1,p=1;
43     for(int i=2;i<=M;i++)
44     {
45         if(!npr[i]) pri[++cnt]=i,mul[i]=-1;
46         for(int j=1;j<=cnt&&i*pri[j]<=M;j++)
47         {
48             npr[i*pri[j]]=true;
49             if(i%pri[j]==0) break;
50             else mul[i*pri[j]]=-mul[i];
51         }
52     }
53     for(int i=1;i<=M;i++) sum[i].idx=i;
54     for(int i=1;i<=M;i++)
55         for(int j=i;j<=M;j+=i) sum[j].f+=i;
56 }
57 int Solve(int n,int m)
58 {
59     int ret=0; 
60     if(n>m) swap(n,m);
61     for(int i=1,j;i<=n;i=j+1)
62     {
63         j=min(n/(n/i),m/(m/i));
64         ret+=(n/i)*(m/i)*(Query(j)-Query(i-1));
65     }
66     return ret&Mod;
67 }
68 int main()
69 {
70     Prework();
71     scanf("%d",&T);
72     for(int i=1;i<=T;i++)
73         scanf("%d%d%d",&qry[i].n,&qry[i].m,&qry[i].a),qry[i].idx=i;
74     sort(qry+1,qry+1+T,cmp);
75     sort(sum+1,sum+1+M,com);
76     for(int i=1;i<=T;i++)
77     {
78         while(p<=M&&sum[p].f<=qry[i].a)
79         {
80             for(int j=sum[p].idx;j<=M;j+=sum[p].idx)
81                 Add(j,mul[j/sum[p].idx]*sum[p].f); p++;
82         }
83         qry[i].ans=Solve(qry[i].n,qry[i].m);
84     }
85     sort(qry+1,qry+1+T,cpr);
86     for(int i=1;i<=T;i++) printf("%d\n",qry[i].ans);
87     return 0;
88 }
View Code

 

posted @ 2019-01-16 14:13  Speranza_Leaf  阅读(150)  评论(0)    收藏  举报