1. 程式人生 > >HDU-1695 GCD(求一個區間內與一個數互質的個數)

HDU-1695 GCD(求一個區間內與一個數互質的個數)

題意:

  給你一個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