RGCDQ(线段树+数论)
Posted leader_win
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RGCDQ(线段树+数论)相关的知识,希望对你有一定的参考价值。
题意:求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(线段树+数论)的主要内容,如果未能解决你的问题,请参考以下文章
暑期集训第一场欧拉回路 | 思维 | 数论构造 | 容斥原理 | 线段树 | 归并排序
Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论
CF1114F Please, another Queries on Array?(线段树,数论,欧拉函数,状态压缩)
CF671C Ultimate Weirdness of an Array 数论线段树
2017 ACM-ICPC, Universidad Nacional de Colombia Programming Contest K - Random Numbers (dfs序 线段树+数论)