1. 程式人生 > >莫(meng)比(bi)烏斯反演--BZOJ2301: [HAOI2011]Problem b

莫(meng)比(bi)烏斯反演--BZOJ2301: [HAOI2011]Problem b

fin 明顯 names 多少 pac 條件 發現 註意 clu

n<=50000個詢問,每次問a<=x<=b,c<=y<=d中有多少gcd(x,y)=K的(x,y)。a,b,c,d,K<=50000。

這大概是入門題辣。。這裏記一波筆記

當難以計算f(i)而易於計算他的反演式g(i)時,可以通過計算g(i)->反演得到f(i)。

先放莫比烏斯函數的性質:$\sum_{d|i} \mu(d)=\left\{\begin{matrix} 1,i=1\\0,i>1\end{matrix}\right.$,$\sum_{d|i}(\mu(d)*n/d)=\varphi(i)$。

反演式一:$g(i)=\sum_{d|i} f(i) ------> f(i)=\sum_{d|i} \mu(d)g(i/d)$。

證明:$\sum_{d|i} \mu(d)g(i/d)=\sum_{d|i} \mu(d) \sum_{d_1|(i/d)} f(d_1)=\sum_{d|i} \sum_{d_1|(i/d)} \mu(d) f(d_1)$。

註意到$dd_1j=i$,所以對每一個$d=d_2$,$d_1=d_3$都有一個$d=d_3$,$d_1=d_2$與之對應。

所以$上式=\sum_{d|i} \sum{d_1|(i/d)} f(d) \mu(d_1)=\sum_{d|i} f(d) \sum{d_1|(i/d)} \mu(d_1)$,由莫比烏斯函數性質得$=f(i)$。

反演式二:$g(i)=\sum_{i|d} f(i) ------> f(i)=\sum_{i|d} \mu(d/i)g(d)$。

證明同上,略。

這題先容斥,變成問1<=x<=n,1<=y<=m中有多少(x,y)=K,由於(x,y)=K的充要條件是(x/K,y/K)=1,所以變成1<=x<=n/K,1<=y<=m/K中有多少(x,y)=1。

為什麽這麽變呢,因為假如題目求的是f(i),表示1<=x<=n,1<=y<=m中有多少(x,y)=i,那反演式g(i)表示1<=x<=n,1<=y<=m中有多少i|(x,y),g(i)和f(i)滿足反演式2。

而明顯的,$g(i)=(n/i)*(m/i)$,這裏/是向下取整,所以$f(i)=\sum_{i|d} \mu(d/i)g(d)=\sum_{i|d} \mu(d/i)(n/d)(m/d)$。

這時可以發現(n/d)和(m/d)分別只有$2\sqrt(n)$和$2\sqrt(m)$種取值,把他倆分別叫a和b,而隨著d增大a和b會緩慢增大,可能a增大b不變,b增大a不變,也可能a,b都增大,都不變。那麽數對((n/d),(m/d))最多只有$2\sqrt(n)+2\sqrt(m)$個,因此(n/d)*(m/d)最多只有$2\sqrt(n)+2\sqrt(m)$種取值。

如果上面的i=1,那麽只需要枚舉這$2\sqrt(n)+2\sqrt(m)$個(n/d)*(m/d)的值就可以在根號時間內算出答案,因為一個(n/d)*(m/d)的值對應一段連續的d,如果i=1,就可以把連續一段莫比烏斯函數以前綴和來O(1)求和。

入門題。

技術分享圖片
 1 #include<cstring>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 //#include<assert.h>
 5 #include<algorithm>
 6 //#include<iostream>
 7 using namespace std;
 8 
 9 int a,b,c,d,K,T;
10 
11 #define maxn 50011
12 int miu[maxn],prime[maxn],lp=0,summiu[maxn]; bool notprime[maxn];
13 void pre(int n=50001)
14 {
15     miu[1]=summiu[1]=1;
16     for (int i=2;i<=n;i++)
17     {
18         if (!notprime[i]) {prime[++lp]=i; miu[i]=-1;}
19         summiu[i]=summiu[i-1]+miu[i];
20         for (int j=1;j<=lp && 1ll*i*prime[j]<=n;j++)
21         {
22             notprime[i*prime[j]]=1;
23             if (i%prime[j]) miu[i*prime[j]]=-miu[i];
24             else {miu[i*prime[j]]=0; break;}
25         }
26     }
27 }
28 
29 #define LL long long
30 LL solve(int p,int q)
31 {
32     LL ans=0;
33     for (int i=1,last,to=min(p,q);i<=to;i=last+1)
34     {
35         last=min(p/(p/i),q/(q/i));
36         ans+=1ll*(p/i)*(q/i)*(summiu[last]-summiu[i-1]);
37     }
38     return ans;
39 }
40 
41 int main()
42 {
43     pre();
44     scanf("%d",&T);
45 while (T--)
46 {
47     scanf("%d%d%d%d%d",&a,&b,&c,&d,&K);
48     printf("%lld\n",solve(b/K,d/K)-solve((a-1)/K,d/K)-solve(b/K,(c-1)/K)+solve((a-1)/K,(c-1)/K));
49 }
50     return 0;
51 }
View Code

莫(meng)比(bi)烏斯反演--BZOJ2301: [HAOI2011]Problem b