[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 }