hdu 6287 口算训练(质因数分解,二分查找)

题目描述:

给出长度为n(n<=1000000)的数列和m(m<=1000000)个询问。

每个询问有三个正整数l,r,d,询问[l,r]区间累乘是否为d的倍数

题目分析:

查询之前先对数列进行质因数分解

记录每一个质数存在的下标,比如数据:2 4 8 16 9 12

那么v[2]={1,2,2,3,3,3,4,4,4,4,6,6}; v[3]={5,5,6};

表示2和3在数据中出现的下标。

那么查询[l,r]=[2,4]中, 有2的多少次方的操作:

upper_bound(v[2].begin(),v[2].end(),r)-lower_bound(v[2].begin(),v[2].end(),l)

答案是9,表示l到r之间最多能够组成2的9次方;

对每个询问中的数d进行质因数分解,再逐个质因数进行查询即可解决。

对某个数进行质因数分解时,分解过程中若d除后为质数,则跳出循环,不然会卡时间

代码:

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#define INF 0x3f3f3f3f//3f3f3f3f
#define lowbit(a) ((a)&(-(a)))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
int n,m,a,l,r,d;
vector<int>v[100005];
int p[100005],np[100005],pcnt;
void primediv(int n){
    memset(np,0,sizeof np);pcnt=0;
    for(int i=2;i<=n;i++){
        if(np[i]==0){
            p[pcnt++]=i;
        }
        for(int j=0;j<pcnt && p[j]*i<=n;j++){
            np[p[j]*i]=1;
            if(i%p[j]==0)break;
        }
    }
}
void resolve(int a, int k){
    for(int i=0;np[a];i++){
        while(a%p[i]==0){
            v[p[i]].push_back(k);
            a/=p[i];
        }
    }
    if(a>1)v[a].push_back(k);//important!
}
int main(){
    primediv(100001);
    int t;
    scanf("%d",&t);
    while(t--){
        for(int i=0;i<pcnt;i++)v[p[i]].clear();
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            resolve(a,i);
        }
        while(m--){
            scanf("%d %d %d",&l,&r,&d);
            int flag=1;
            for(int i=0, num=0;np[d] && flag;i++){
                while(d%p[i]==0)
                    d/=p[i],num++;
                if(num){
                    int cnt=upper_bound(v[p[i]].begin(),v[p[i]].end(),r)
                            -lower_bound(v[p[i]].begin(),v[p[i]].end(),l);
                    if(cnt<num)flag=0;
                    num=0;
                }
            }
            if(flag && d>1){//important
                int cnt=upper_bound(v[d].begin(),v[d].end(),r)
                        -lower_bound(v[d].begin(),v[d].end(),l);
                if(cnt<1)flag=0;
            }
            if(flag)printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kzn2683331518/article/details/81155943