HDU-1695 GCD(求一個區間內與一個數互質的個數)
阿新 • • 發佈:2018-11-02
題意:
給你一個T,是樣例的個數,接下來是五個數l1,r1,l2,r2,k 前四個數代表兩個區間(l1,r1),(l2,r2)這個題l1=1,l2=1;
取x1屬於(1,r1),x2屬於(1,r2);
求使得gcd(x1,x2)==k 的(x1,x2)的個數,特別的(1,2)和(2,1)只計算一次;
思路:
他讓求gcd等於k的 我們可以讓r1,r2都除以k相當於求 取x1屬於(1,r1/k),x2屬於(1,r2/k); 求使得gcd(x1,x2)==1 的(x1,x2)的個數,就相當於求兩個區間內互質的數可以組成幾組
那麼 這個題就簡單了,,套上求一個區間內與一個數互質的個數的模板就A了
AC程式碼如下;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> using namespace std; typedef long long ll; const int maxn=1e6+5; vector<ll> p[maxn]; void getpri(ll kk)//這裡先把每個數的素因子篩選出來,,因為這個題資料大,需要預處理一下1到1e5的素因子,防止超時 { ll x=kk; for(ll i=2;i*i<=x;i++) { if(x%i==0) { p[kk].push_back(i); while(x%i==0) x/=i; } } if(x>1)p[kk].push_back(x); } ll solve(ll x,ll r)//這裡就是求一個區間內的與一個數互質的個數的模板; { ll ans=0; for(ll i=1;i<(1<<p[x].size());i++) { ll cnt=0; ll mult=1; for(ll j=0;j<p[x].size();j++) { if(i&(1<<j)) { cnt++; mult*=p[x][j]; } } mult=r/mult; if(cnt&1) ans+=mult; else ans-=mult; } if(ans<0)ans=0; if(r-ans<0)return 0; return r-ans; } int main() { int T,t=1; for(int i=1;i<maxn;i++) getpri(i); scanf("%d",&T); while(T--) { ll l1,r1,r2,l2,k; scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&k); if(k==0)//特別要注意這個題一個坑點,,k可能等於0!!!!!!!! { printf("Case %d: 0\n",t++); continue; } r1/=k;r2/=k; ll ans=0; if(r1>r2)swap(r1,r2);//找出大區間 for(ll i=1;i<=r2;i++)//這裡遍歷大區間,對於每個小於等於r1的數x1先求一下小於等於x1的與x1互質的個數,之後的x2>r1 求(1,r1)區間內與x2互質的個數
{
//比如(1,5),(1,10)
//先求(1,1)內和1互質的個數,再求(1,2)內與2互質的個數,再求(1,3)與3,再求(1,4)與4,再求(1,5)與5,後面的就是求6,7,8,9,10分別與(1,5)內互質的個數
ans+=solve(i,min(i,r1)); } printf("Case %d: %lld\n",t++,ans); } return 0; }
這個題還有另一種模板,就是深搜模板想了解一下的朋友詳見
https://www.cnblogs.com/1013star/p/9896262.html