牛客练习赛58 E-最大GCD(gcd)

传送门

题意:

在这里插入图片描述

思路:

要想让 [ 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 <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
#include <stack>
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);
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值