[bzoj2301]Problem b莫比乌斯反演+分块优化

题意:

$\sum\limits_{\begin{array}{*{20}{c}}
{a < = x < = b}\\
{c < = y < = d}
\end{array}} {\gcd (x,y) = = k} $

解题关键:

现令$f(i)$表示有多少对${(x,y)}$满足 ${\gcd (x,y) =  = d}$,$1 <  = x <  = n,1 <  = y <  = m$

 $F(d)$为有多少对${(x,y)}$满足 ${\gcd (x,y) =  = d}$的倍数

$f(d) = \sum\limits_{\begin{array}{*{20}{c}}
{1 < = x < = n}\\
{1 < = y < = m}
\end{array}} {\gcd (x,y) = = d} $

$\begin{array}{l}
F(d) = \frac{n}{d} * \frac{m}{d}\\
\begin{array}{*{20}{l}}
{F(d) = \sum\limits_{d|x} {f(x)} \Rightarrow }\\
{f(d) = \sum\limits_{d|x} {u(\frac{x}{d})F(x)} = \sum\limits_{d|x} {u(\frac{x}{d})\left\lfloor {\frac{n}{x}} \right\rfloor } \left\lfloor {\frac{m}{x}} \right\rfloor }
\end{array}\\
= \sum\limits_{d|x}^{\min (n,m)} {u(\frac{x}{d})} \left\lfloor {\frac{n}{x}} \right\rfloor \left\lfloor {\frac{m}{x}} \right\rfloor
\end{array}$

再根据二维前缀和的型,$ans = g(b,d,k) + g(a - 1,c - 1,k) - g(a - 1,d,k) - g(b,c - 1,k)$

法二:稍微转化一下。

$\begin{array}{*{20}{l}}
{f(d) = {\sum _{\begin{array}{*{20}{c}}
{1 < = x < = n}\\
{1 < = y < = m}
\end{array}}}\gcd (x,y) = = d}\\
{ = {\sum _{\begin{array}{*{20}{c}}
{1 < = x < = n}\\
{1 < = y < = m}
\end{array}}}\gcd (\frac{x}{d},\frac{y}{d}) = = 1}\\
{\begin{array}{*{20}{l}}
{ = {\sum _{\begin{array}{*{20}{c}}
{1 < = x < = \frac{n}{d}}\\
{1 < = y < = \frac{m}{d}}
\end{array}}}\gcd (x,y) = = 1}\\
{ = \sum\limits_{i = 1}^{\min (\frac{n}{d},\frac{m}{d})} u (i)F(i)}
\end{array}}\\
{ = \sum\limits_{i = 1}^{\min (\frac{n}{d},\frac{m}{d})} u (i)\left\lfloor {\frac{n}{{di}}} \right\rfloor \left\lfloor {\frac{m}{{di}}} \right\rfloor }\\
{}
\end{array}$

预处理前缀和+分块,$n/i$这种类型的一般要考虑重复性,利用分块可以优化到根号的复杂度。

观察式子,会发现$\left\lfloor {\frac{n}{d}} \right\rfloor $最多有$2\sqrt n $个取值,同理,$\left\lfloor {\frac{m}{d}} \right\rfloor $最多有$2\sqrt m $个取值,枚举这$2(\sqrt n  + \sqrt m )$个取值,对莫比乌斯函数维护一个前缀和,可以在$O(\sqrt n )$内求出解。

n/(n/i)就是满足商为n/i的i的最大值

复杂度的详细证明:http://blog.csdn.net/outer_form/article/details/50590197

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 //莫比乌斯函数线性筛法
 5 const int maxn=100000+5;
 6 bool vis[maxn];
 7 int prime[maxn],mu[maxn],sum1[maxn];
 8 void init_mu(int n){
 9     int cnt=0;
10     mu[1]=1;
11     for(int i=2;i<n;i++){
12         if(!vis[i]){
13             prime[cnt++]=i;
14             mu[i]=-1;
15         }
16         for(int j=0;j<cnt&&i*prime[j]<n;j++){
17             vis[i*prime[j]]=1;
18             if(i%prime[j]==0)   {mu[i*prime[j]]=0;break;}
19             else { mu[i*prime[j]]=-mu[i];}
20         }
21     }
22     for(int i=1;i<n;i++){
23         sum1[i]=sum1[i-1]+mu[i];
24     }
25 }
26 inline int read(){
27     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
28     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
29     if(k=='-')x=0-x;return x;
30 }
31 int fun(int n,int m,int k){
32     n/=k,m/=k;
33     if(n>m) swap(n,m);
34     int ans=0,pos;
35     for(int i=1;i<=n;i=pos+1){
36         pos=min(n/(n/i),m/(m/i));
37         ans+=(sum1[pos]-sum1[i-1])*(n/i)*(m/i);
38     }
39     return ans;
40 }
41 int main(){
42     int t,a,b,c,d,k;
43     init_mu(100001);
44     t=read();
45     while(t--){
46         a=read(),b=read(),c=read(),d=read(),k=read();
47         int t1=fun(b,d,k),t2=fun(a-1,c-1,k),t3=fun(a-1,d,k),t4=fun(b,c-1,k);
48         int ans=t1+t2-t3-t4;
49         printf("%d\n",ans);
50     }
51 }

 

  

posted @ 2017-08-29 03:59  Elpsywk  阅读(201)  评论(0编辑  收藏  举报