1. 程式人生 > 實用技巧 >離散化+分解質因子

離散化+分解質因子

傳送門

題目求[A,B]區間內與N互質數的個數。

  • 可以通過求出區間內與N互質數的個數的字首和,即[1,X],來得出[A,B]。
  • 那麼現在問題是求出[1,X]區間內與N互質數的個數,考慮這個問題的逆問題:[1,X]區間內與N不互質數的個數。
  • 於是就可以先處理出N的所有質因數{p0,p1,p2,...,pn}。
  • 而[1,X]能被pi整除的數有X/pi個,再利用容斥原理除掉質因數公倍數重複計數的部分就能求出不互質個數。
  • 最後X減去不互質個數就是互質個數了。

但求不互質的過程中存在重複(如,質因子2,3的的倍數都有6),需要容斥(奇加偶減),可將所有質因子看成一串二進位制編碼,

算出即可

#include<algorithm>
#include
<iostream> typedef long long ll; using namespace std; const int maxn=1e6+100; ll l,r,x; int cnt=0; int a[maxn]; void inint(ll x){ cnt=0; for(ll i=2;i*i<=x;i++){//分解質因子 if(x%i!=0){ continue; } while(x%i==0){ x/=i; } a[cnt++]=i; }
if(x>1){ a[cnt++]=x; } } ll solve(ll x){ ll ans=x; for(ll i=1;i<(1<<cnt);i++){//二進位制列舉 ll p=1,flag=0; for(ll j=0;j<cnt;j++){ if(i&(1<<j)){ p*=a[j]; flag++; } } //例如 3 5 7吧,就是x-x/3-x/5-x/7+x/15+x/21+x/35-x/105
if(flag&1){//奇數減 ans-=x/p; } else{//偶數加 ans+=x/p; } } return ans; } int main(){ int t; cin>>t; int kase=0; while(t--){ scanf("%lld%lld%lld",&l,&r,&x); inint(x); printf("Case #%d: ",++kase); printf("%lld\n",solve(r)-solve(l-1)); } }