RGCDQ(線段樹+數論)
阿新 • • 發佈:2018-01-13
func prim std stdlib.h cli size pop 之間 分析
題意:求n和m之間的全部數的素因子個數的最大gcd值。
分析:這題好惡心。看著就是一顆線段樹。但本題有一定的規律,我也是後來才發現,我還沒推出這個規律。就不說了,就用純線段樹解答吧。
由於個點數都小於1000000所以素因子個數不會超過7個所以建一個線段樹,最以下一層是每一個節點的素因子個數為1,2。3,4,5,6。7的有多少個,父節點求和。終於查詢的是n到m之間有多少個1,2,3。4。5,6,7然後存在就求一下gcd著最大就好了
本題最重要的時間和空間。顯然線段數中的點不會非常大,所以採用short類型
代碼例如以下:
#include <set> #include <map> #include <stack> #include <queue> #include <math.h> #include <vector> #include <string> #include <utility> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <functional> using namespace std; int gcd(int a,int b){ return (b==0)?a:gcd(b,a%b); } const int N=100000; int prime[N]={0}; int num_prime=0; bool isNotPrime[N]={1,1}; void su1(){ for(long i = 2 ; i < N ; i ++){ if(!isNotPrime[i]) prime[num_prime++]=i; for(long j = 0 ; j < num_prime &&i*prime[j]<N ;j ++) { isNotPrime[i * prime[j]] = 1; if( !(i % prime[j]))break; } } } int prime_solve(int n){ int k=0; for(int i=0;i<num_prime&&prime[i]*prime[i]<=n;i++){ // cout<<prime[i]<<endl; if(n%prime[i]==0){ while(n%prime[i]==0){ n/=prime[i]; } k++; } } if(n!=1)k++; return k; }//素因子分解求n的素因子個數 short a[4000005][8]; void updat(int id,int j,int l,int r,int mid){ if(l==r){ a[mid][j]=1; return; } int i=(l+r)>>1; if(id<=i)updat(id,j,l,i,2*mid); else updat(id,j,i+1,r,2*mid+1); a[mid][j]=a[2*mid][j]+a[2*mid+1][j]; } int sum[8]; void su(int l,int r,int mid,int ll,int rr){ if(l>=ll&&r<=rr){ for(int i=1;i<=7;i++) sum[i]+=a[mid][i]; return; } int i=(l+r)>>1; if(ll<=i)su(l,i,2*mid,ll,rr); if(rr>i)su(i+1,r,2*mid+1,ll,rr); }//建樹,求和,這是重點 int main(){ memset(a,0,sizeof(a)); su1(); // for(int i=1;i<=100;i++){ // if(isNotPrime[i]) // cout<<i<<" "<<prime_solve(i)<<endl;; // } // cout<<endl; for(int i=2;i<=1000005;i++){ int d=prime_solve(i); updat(i,d,2,1000005,1); } int n,m; int t; cin>>t; while(t--){ scanf("%d%d",&n,&m); memset(sum,0,sizeof(sum)); su(2,1000005,1,n,m); int ans=-1; for(int i=1;i<=7;i++) for(int j=1;j<=7;j++){ if(i==j){ if(sum[i]>1)ans=max(ans,gcd(i,j)); } else{ if(sum[i]>0&&sum[j]>0)ans=max(ans,gcd(i,j)); } }//這個地方就能夠純暴力了 printf("%d\n",ans); } return 0; }
RGCDQ(線段樹+數論)