HDU - 6287 口算训练(分解质因数&区间查询因数个数)

这里写图片描述

给出数列,给出区间,查询区间内值之积是否能整除给出的数字X。

那么即查询数字X的质因数个数是否符合区间内所有值的质因数个数。一旦每个质因数个数都大于X的质因数个数,即可以整除X。

首先预处理出序列中所有数的质因数。然后哈希记录每个质因数都在哪些位置的数值上出现了。如,质数2是位置1,3,4,5的值的质因数。并且,如果一个位置上的值出现了多次同一个质因数,也就是说如数值8在位置3,那么8内有3个质因数2,因此质数2内存储的形式则是3,3,3。

通过这样的存储结果将1e5内的所有质数出现的位置和次数都按照序列从小到大的顺序记录下来。这样对于一个质数,可以知道在哪些区间出现了多少次。

接着判断X,将其分解质因数,计算每一个质因数在区间L~R内出现的次数,再与其分解出的质因数个数比较。一旦有不符的直接判断不为倍数。具体方法是,之前已经在数组中记录了每个质数的出现次数和位置,那么针对一个数组,用位置L和R二分找到其第一次出现L和最后一次出现R的位置,作差,这段距离就是L到R内该质数出现的次数。注意最后判断最终剩下的一个值如果不是1的话还应继续判断其质数在区间内是否存在。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m;
vector<int>p[maxn];
void prim(int x,int pos)
{
    for(int i=2; i*i<=x; i++)
    {
        while(x%i==0)
        {
            p[i].push_back(pos);
            x/=i;
        }
    }
    if(x>1)p[x].push_back(pos);
}
int check(int l,int r,int x)
{
    return upper_bound(p[x].begin(),p[x].end(),r)-lower_bound(p[x].begin(),p[x].end(),l);
}///直接在某个因数中查询第pos个位置的值被分解出了多少个x,也就是连续多少pos
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        for(int i=0; i<maxn; i++)p[i].clear();
        int tmp;
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&tmp);
            prim(tmp,i);
        }
        while(m--)
        {
            int l,r;
            bool ans=true;
            scanf("%d%d%d",&l,&r,&tmp);
            for(int i=2; i*i<=tmp; i++)
            {
                int sum=0;
                while(tmp%i==0)sum++,tmp/=i;
                if(sum>check(l,r,i))
                {
                    ans=false;
                    break;
                }
            }
            if(ans&&tmp>1&&check(l,r,tmp)==0)ans=false;
            printf("%s\n",ans?"Yes":"No");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/80768347
今日推荐