[SDOI2015]约数个数和

题目描述

设d(x)为x的约数个数,给定N、M,求 ij d(i*j)  (i<=n,j<=m)

输入输出格式

输入格式:

输入文件包含多组测试数据。第一行,一个整数T,表示测试数据的组数。接下来的T行,每行两个整数N、M。

输出格式:

T行,每行一个整数,表示你所求的答案。

输入输出样例

输入样例#1:
2
7 4
5 6
输出样例#1:
110
121

说明

1<=N, M<=50000

1<=T<=50000

题解:

已知推论:d(i*j)=∑ab[gcd(a,b)=1]  (a|i , b|j)

原式化为

ijab[gcd(a,b)=1]   (1<=i<=n&&1<=j<=m)

=∑ijabdμ(d)       (d|a,d|b,d|i,d|j)

=ijdμ(d)ab1     (d|i,d|j,1<=a<=n/i,1<=b<=m/j)   

=ijdμ(d)*[n/i][m/j]

=dμ(d)ij[n/id][m/jd]  (1<=d<=min(n,m),i<=n/d,j<=m/d)

=dμ(d)*i[n/id]*j[m/jd]=dμ(d)*i[[n/d]/i]*j[[m/d]/j]

令f(x)=∑[x/i] (1<=i<=x) 

接下来用分块的方法在O(N√N)时间求出f(1~n)

分块详见我写的http://www.cnblogs.com/Y-E-T-I/p/7255421.html

每一次询问的时候也用分块的方法求ans=∑dμ(d)*[f(n/d)]*[f(m/d)]

不过第三行似乎是多余的

这个结论要记下来

延伸结论

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 bool vis[50001];
 7 int tot,prime[50001],mu[50001],n,m;
 8 long long ans,d[50001];
 9 void mobius()
10 {int i,j;
11 mu[1]=1;
12     for (i=2;i<=50000;i++)
13     {
14         if (vis[i]==0)
15         {
16             tot++;
17             prime[tot]=i;
18             mu[i]=-1;
19         }
20         for (j=1;j<=tot,i*prime[j]<=50000;j++)
21          {
22              vis[i*prime[j]]=1;
23              if (i%prime[j]==0)
24              {
25                  mu[i*prime[j]]=0;
26                  break;
27             }
28                  mu[i*prime[j]]=-mu[i];
29          }
30     }
31     for (i=1;i<=50000;i++)
32     mu[i]+=mu[i-1];
33 }
34 void solve(int x)
35 {int i;
36     int pos=1;
37     for (i=1;i<=x;i=pos+1)
38     {
39         pos=x/(x/i);
40          d[x]+=(pos-i+1)*(x/i);
41     }
42 }
43 void work()
44 {int i;
45     ans=0;
46     int pos=1;
47     for (i=1;i<=n;i=pos+1)
48     {
49         pos=min(n/(n/i),m/(m/i));
50         ans+=(mu[pos]-mu[i-1])*(d[n/i])*(d[m/i]);
51     }
52 }
53 int main()
54 {int i,T;
55     mobius();
56      for (i=1;i<=50000;i++)
57      solve(i);
58       cin>>T;
59       while (T--)
60       {
61         scanf("%d%d",&n,&m);
62         if (n>m) swap(n,m);
63          work();
64          printf("%lld\n",ans);
65       }
66 }

 

posted @ 2017-08-03 15:32  Z-Y-Y-S  阅读(162)  评论(0编辑  收藏  举报