1. 程式人生 > >洛谷 P2257 YY的GCD

洛谷 P2257 YY的GCD

而且 分塊 處理 def 數據 gcd 在一起 return 整數

YY的GCD

題目描述

神犇YY虐完數論後給傻×kAc出了一題

給定\(N\), \(M\) ,求\(1 \le x \le N,1 \le y \le M\)\(gcd(x, y)\)為質數的\((x, y)\)有多少對

kAc這種傻×必然不會了,於是向你來請教……

多組輸入

輸入輸出格式

輸入格式:

第一行一個整數\(T\)表述數據組數

接下來T行,每行兩個正整數,表示\(N,M\)

輸出格式:

\(T\)行,每行一個整數表示第\(i\)組數據的結果

說明

\(T = 10000\)
\(N, M \le 10000000\)

Solution

思路:按反演的套路把式子列出來以後,通過想辦法操作求和,把好算的放在一起,\(\mu\)

一個人呆。

以下\(f(x)=\sum_{i=1}^a\sum_{j=1}^b[gcd(a,b)=x]\)\(g(x)=\lfloor\frac{a}{x}\rfloor \lfloor \frac{b}{x} \rfloor\)\(p\)代表質數集合

\[\sum_{i=1}^a\sum_{j=1}^b[gcd(a,b) \in p]\]

\[=\sum_{n \in p}f(n)\]

\[=\sum_{n \in p}\sum_{n|d}^{min(a,b)}\mu(\frac{d}{n})g(d)\]

\[=\sum_{n \in p}\sum_{k=1}^{\min(\lfloor \frac{a}{n} \rfloor, \lfloor \frac{b}{n} \rfloor)}\mu(k)\lfloor\frac{a}{kn}\rfloor \lfloor\frac{b}{kn}\rfloor\]

現在我們不想讓\(\mu\)和別人呆在一起,因為兩個求和之間也沒夾個什麽東西,不妨把它們換一換,直接換肯定不行,得找一波操作。

\(T=kn\),則有\(k=\frac{T}{n}\),上式就等於

\[=\sum_{T=1}^{min(a,b)}\sum_{n|T,n\in p}\mu(\frac{T}{n})\lfloor\frac{a}{T}\rfloor\lfloor\frac{b}{T}\rfloor\]

\[=\sum_{T=1}^{min(a,b)}\lfloor\frac{a}{T}\rfloor\lfloor\frac{b}{T}\rfloor\sum_{n|T,n\in p}\mu(\frac{T}{n})\]

後面那個感覺預處理還挺慢的,但根據調和級數不會慢於\(O(nlnn)\),而且跑一下發現才\(3e7\)多運算。

預處理完後面那個就可以除法分塊回答詢問了。


Code:

#include <cstdio>
#define ll long long
const int N=1e7;
int mu[N+10],f[N+10],pri[N+10],ispri[N+10],cnt,a,b,T;
void init()
{
    mu[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!ispri[i])
        {
            mu[i]=-1;
            pri[++cnt]=i;
        }
        for(int j=1;j<=cnt&&pri[j]*i<=N;j++)
        {
            ispri[pri[j]*i]=1;
            if(i%pri[j]==0) break;
            else mu[pri[j]*i]=-mu[i];
        }
    }
    for(int i=1;i<=cnt;i++)
        for(int j=pri[i];j<=N;j+=pri[i])
            f[j]+=mu[j/pri[i]];
    for(int i=1;i<=N;i++)
        f[i]+=f[i-1];
}
int min(int x,int y){return x<y?x:y;}
int main()
{
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&a,&b);
        ll ans=0;
        for(int l=1,r;l<=min(a,b);l=r+1)
        {
            r=min(a/(a/l),b/(b/l));
            ans+=1ll*(a/l)*(b/l)*(f[r]-f[l-1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

2018.10.19

洛谷 P2257 YY的GCD