传送门
要想让 [ l , r ] [l,r] [l,r],选出来个区间的 g c d gcd gcd值最大,最优是,只有在 [ l , r ] [l,r] [l,r]区间找一个值使得 g c d ( x , a [ i ] ) gcd(x,a[i]) gcd(x,a[i])最大即可, x x x一定是 a [ i ] a[i] a[i]的因子
因此我们先处理每一个 a [ i ] a[i] a[i],用一个 v e c t o r vector vector,把 a [ i ] a[i] a[i]的所有因子里都放入 i i i,意思就是该因子在i位置可以得到
然后对于每次询问,我们遍历 x x x的每一个因子 k k k,如果该因子能够在 l , r l,r l,r范围内找到,与结果相比取最大值即可
查询一个数在能不能在 l , r l,r l,r范围内找到用二分
lower_bound( )lower_bound( )的用法
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long ll;
#define PII make_pair
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int MAXN=1e5+50;
const int inf=0x3f3f3f3f;
const int M=5000*4;
vector<int>p[MAXN];
bool check(int x,int l,int r){
int len=p[x].size();
if(len==0||p[x][0]>r||p[x][len-1]<l)return 0;
int pos=lower_bound(p[x].begin(),p[x].end(),l)-p[x].begin();
if(p[x][pos]<=r) return 1;
else return 0;
}
int main()
{
int n,q,x;
scanf("%d%d",&n,&q);
rep(i,1,n){
scanf("%d",&x);
for(int j=1;j*j<=x;j++){
if(x%j==0){
p[j].pb(i);
if(j!=x/j)p[x/j].pb(i);
}
}
}
int l,r;
while(q--){
int ans=0;
scanf("%d%d%d",&l,&r,&x);
for(int i=1;i*i<=x;i++){
if(x%i==0){
if(check(i,l,r))
ans=max(ans,i);
if(check(x/i,l,r))
ans=max(ans,x/i);
}
}
printf("%d\n",ans);
}
return 0;
}
另一种写法,用了两次二分,只过了91%的样例,有点超时
int l,r;
while(q--){
int ans=0;
scanf("%d%d%d",&l,&r,&x);
for(int i=1;i*i<=x;i++){
if(x%i==0){
if(lower_bound(p[i].begin(),p[i].end(),l)!=upper_bound(p[i].begin(),p[i].end(),r))
ans=max(ans,i);
if(lower_bound(p[x/i].begin(),p[x/i].end(),l)!=upper_bound(p[x/i].begin(),p[x/i].end(),r))
ans=max(ans,x/i);
}
}
printf("%d\n",ans);
}