1. 程式人生 > 實用技巧 >BZOJ-3834 [Poi2014]Solar Panels(數論分塊)

BZOJ-3834 [Poi2014]Solar Panels(數論分塊)

題目描述

  已知 \(A\leq x\leq B,C\leq y\leq D\),求 \(\gcd(x,y)\) 的最大值。

  資料範圍:\(1\leq T\leq 1000,1\leq A\leq B\leq 10^9,1\leq C\leq D\leq 10^9\)

分析

  考慮列舉 \(x,y\) 的公因子 \(d\)

  首先可以發現一個性質:區間 \([l,r]\) 中有 \(d\) 的倍數的充要條件是 \(\lfloor\frac{l-1}{d}\rfloor<\lfloor\frac{r}{d}\rfloor\)

  列舉 \(d\in [1,\min(B,D)]\),然後判斷是否滿足 \(\lfloor\frac{A-1}{d}\rfloor<\lfloor\frac{B}{d}\rfloor\)

\(\lfloor\frac{C-1}{d}\rfloor<\lfloor\frac{D}{d}\rfloor\)。可以發現 \(\lfloor\frac{D}{d}\rfloor\) 這種形式的式子可以分塊算,最多隻有 \(\sqrt{D}\) 種取值,每一塊中 \(d\) 的最大值為 \(\min\Big(\Big\lfloor\frac{B}{\lfloor\frac{B}{l}\rfloor}\Big \rfloor,\Big\lfloor\frac{D}{\lfloor\frac{D}{l}\rfloor}\Big \rfloor\Big)\),因此分塊列舉即可。

程式碼

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        long long A,B,C,D,ans;
        scanf("%lld %lld %lld %lld",&A,&B,&C,&D);
        for(long long l=1,r;l<=B&&l<=D;l=r+1)
        {
            r=min(B/(B/l),D/(D/l));
            if( (A-1)/r<B/r and (C-1)/r<D/r)
                ans=r;
        }
        cout<<ans<<endl;
    }
}