题意:一个数列,q个询问,问某个区间,如果某个数是其他数的因子,则s++,问r-l+1-s是多少
思路:一个数是其他数的因子,这个数肯定是最小数,且为这个区间的gcd,所以RMQ求区间GCD,区间最小值,在用线段树求这个区间最小值个数
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 6 ll dp1[N][20],dp2[N][20],a[N]; 7 int n; 8 9 void init(){ 10 memset(dp2,127,sizeof(dp2)); 11 for(int i=1;i<=n;i++) 12 dp1[i][0]=dp2[i][0]=a[i]; 13 for(int j=1;(1<<j)<=n;j++){ 14 for(int i=1;i+(1<<j)-1<=n;i++) 15 { 16 dp1[i][j]=__gcd(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]); 17 dp2[i][j]=min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]); 18 } 19 } 20 } 21 int check(int x,int y){ 22 int kk=0; 23 while((1<<(kk+1))<=y-x+1) kk++; 24 int Min=min(dp2[x][kk],dp2[y-(1<<kk)+1][kk]); 25 return Min; 26 } 27 int check1(int x,int y){ 28 int kk=0; 29 while((1<<(kk+1))<=y-x+1) kk++; 30 int Min=__gcd(dp1[x][kk],dp1[y-(1<<kk)+1][kk]); 31 return Min; 32 } 33 struct node{ 34 int l,r,M,num; 35 }e[N*4]; 36 37 void build(int x,int L,int R){ 38 e[x].l=L;e[x].r=R; 39 40 if(L==R){ 41 e[x].M=a[L];e[x].num=1;return ; 42 } 43 int mid=(L+R)>>1; 44 build(2*x,L,mid); 45 build(2*x+1,mid+1,R); 46 if(e[2*x].M==e[2*x+1].M){ 47 e[x].M=e[2*x].M; 48 e[x].num=e[x*2].num+e[2*x+1].num; 49 } 50 else { 51 if(e[2*x].M<e[2*x+1].M){ 52 e[x].M=e[2*x].M;e[x].num=e[2*x].num; 53 } 54 else 55 { 56 e[x].M=e[2*x+1].M;e[x].num=e[2*x+1].num; 57 } 58 } 59 } 60 61 int sum; 62 void query(int x,int L,int R,int y){ 63 if(e[x].l>=L&&R>=e[x].r){ 64 if(e[x].M==y) { 65 sum+=e[x].num; 66 } 67 return ; 68 } 69 int mid=(e[x].l+e[x].r)>>1; 70 if(mid>=R) query(2*x,L,R,y); 71 else if(L>mid) query(2*x+1,L,R,y); 72 else { 73 query(2*x,L,mid,y); 74 query(2*x+1,mid+1,R,y); 75 } 76 } 77 int main(){ 78 scanf("%d",&n); 79 for(int i=1;i<=n;i++){ 80 scanf("%d",&a[i]); 81 } 82 build(1,1,n); 83 init(); 84 int q; 85 86 cin>>q; 87 int x,y; 88 while(q--){ 89 scanf("%d%d",&x,&y); 90 ll z=check(x,y); 91 ll zz=check1(x,y); 92 // cout<<z<<" "<<zz<<endl; 93 if(z==zz){ 94 sum=0; 95 query(1,x,y,zz); 96 printf("%d\n",y-x+1-sum); 97 } 98 else { 99 printf("%d\n",y-x+1); 100 } 101 } 102 }