神犇YY虐完數論後給傻×kAc出了一題給定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)爲質數的(x, y)有多少對kAc這種html
傻×必然不會了,因而向你來請教……多組輸入c++
第一行一個整數T 表述數據組數接下來T行,每行兩個正整數,表示N, Mgit
T行,每行一個整數表示第i組數據的結果函數
2 10 10 100 100
30 2791
T = 10000spa
N, M <= 10000000code
前置知識:莫比烏斯反演htm
題目讓咱們求這個:
\[ ans=\sum_{i=1}^n\sum_{j=1}^m [gcd(i,j) \in pri]\\ \]
其中\(pri\)表示質數集合。blog
而後枚舉這個質數:
\[ \begin {align} ans&= \sum _{d\in pri} \sum _{i=1}^{n} \sum _{j=1}^{m} [gcd(i,j)=d]\\ &=\sum _{d\in pri} \sum _{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum _{j=1}^{\lfloor \frac{m}{d} \rfloor} [gcd(i,j)=1] \\ \end {align} \]
根據莫比烏斯函數的性質能夠獲得:
\[ \sum _{d ^\prime|n} \mu(d ^\prime)=[n=1] \]
而後把\(n\)換成\(gcd(i,j)\)帶進去,得:
\[ ans=\sum _{d\in pri} \sum _{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum _{j=1}^{\lfloor \frac{m}{d} \rfloor} \sum _{d^\prime|i \&d^\prime|j} \mu (d^\prime) \]
而後先枚舉\(d^\prime\),得:
\[ \begin{align} ans&=\sum _{d\in pri} \sum _{d^\prime} \mu (d^\prime) \sum _{i=1}^{\lfloor \frac{n}{dd^\prime} \rfloor} \sum _{j=1}^{\lfloor \frac{m}{dd^\prime} \rfloor} 1\\ ans&= \sum _{d\in pri} \sum _{d^\prime} \mu(d^\prime) \lfloor \frac{n}{dd^\prime}\rfloor \lfloor\frac{m}{dd^\prime}\rfloor \end {align} \]
令\(T=dd^\prime\),得:
\[ \begin{align} ans&= \sum _{d \in pri } \sum _{T}\mu(\frac{T}{d}) \lfloor \frac{n}{T}\rfloor \lfloor\frac{m}{T}\rfloor \\ &= \sum _{T}\lfloor \frac{n}{T}\rfloor \lfloor\frac{m}{T}\rfloor \sum _{d \in pri \& d|T} \mu(\frac{T}{d}) \end {align} \]ip
\[ \begin {align} &\text{令}f(n) = \sum _{d\in pri \& d|T} \mu (d) \\ &ans= \sum _{T}\lfloor \frac{n}{T}\rfloor \lfloor\frac{m}{T}\rfloor f(T) \end {align} \]get
線篩出質數和\(\mu\)函數以後,暴力預處理\(f\)並求出前綴和,而後數論分塊就好了。
因爲n之內的質數只有\(O(n/ln(n))\)個,因此預處理複雜度爲\(O(n/ln(n)*ln(n/ln(n))+n)=O(n)\),具體參考調和級數。
而後詢問的複雜度爲\(O(q\sqrt{n})\)。
#include<bits/stdc++.h> using namespace std; #define int long long void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} const int maxn = 1e7+1; int mu[maxn+10],sum[maxn+10],pri[maxn+10],tot,vis[maxn+10],n,m; void time() {cerr << (double) clock()/CLOCKS_PER_SEC << endl;} void sieve() { mu[1]=1; for(int i=2;i<maxn;i++) { if(!vis[i]) pri[++tot]=i,mu[i]=-1; for(int j=1;j<=tot&&i*pri[j]<maxn;j++) { vis[i*pri[j]]=1; if(!(i%pri[j])) {mu[i*pri[j]]=0;break;} mu[i*pri[j]]=-mu[i]; } }//time();write(tot); for(int i=1;i<=tot;i++) for(int j=1;j*pri[i]<maxn;j++) sum[j*pri[i]]+=mu[j]; for(int i=1;i<maxn;i++) sum[i]=sum[i]+sum[i-1]; //time(); } signed main() { sieve();int asd;read(asd); //for(int i=1;i<=10;i++) write(sum[i]); while(asd--) { read(n),read(m); if(n>m) swap(n,m); int T=1,ans=0; while(T<=n) { int pre=T;T=min(n/(n/T),m/(m/T)); ans+=(n/pre)*(m/pre)*(sum[T]-sum[pre-1]); T++; } write(ans); } return 0; }