口算训练

口算训练

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 939    Accepted Submission(s): 173


Problem Description
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为 n的正整数序列 a1,a2,...,an,要求小T抛出 m个问题以训练他的口算能力。

每个问题给出三个正整数 l,r,d,小Q需要通过口算快速判断 al×al+1×...×ar1×ar是不是 d的倍数。

小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
 

Input
第一行包含一个正整数 T(1T10),表示测试数据的组数。

每组数据第一行包含两个正整数 n,m(1n,m100000),分别表示序列长度以及问题个数。

第二行包含 n个正整数 a1,a2,...,an(1ai100000),表示序列中的每个数。

接下来 m行,每行三个正整数 l,r,d(1lrn,1d100000),表示每个问题。
 

Output
对于每个问题输出一行,若是倍数,输出Yes,否则输出No。
 

Sample Input
 
 
1 5 4 6 4 7 2 5 1 2 24 1 3 18 2 5 17 3 5 35
 

Sample Output
 
 
Yes No No Yes
 

Source
 

Recommend
liuyiding




所以刚开使我想用一个map把这组数里面的所有因数的数量给计算出来,然后进行mp[r][x]-mp[l-1][x]是否>=k(kd里头含有x的数量)但是后来我发现要么map是不会中途释放空间的,所以空间会爆炸,然后我用了一些时间来压缩空间,那就会超时,所以两种方法都不可以用,那么稍微换一点思路。

我们用一个vector来记录因素x出现在哪几个位子上,比如样例的6 4 7 2 5就可以写成v[2]={1,2,2,4},v[3]={1},v[5]={5},v[7]={7};这样,我们就可以通过二分来查其中出现的数量了,具体参考代码



#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int x;
vector<int> p[100005];
void shuru(int j,int y){
    for (int i = 2; i*i <= y; i++)
    {
        while (y%i == 0)
        {
            p[i].push_back(j);
            y/=i;
        }
    }
    if (y > 1) p[y].push_back(j);
}
bool panduan(int d,int l,int r){
    int t;
    for(int i=2;i*i<=d;i++){
        t=0;
        while(d%i==0){
            t++;
            d=d/i;
        }
        if(t>0&&upper_bound(p[i].begin(), p[i].end(), r)- lower_bound(p[i].begin(), p[i].end(), l)<t)
            return false;
    }
    if(d>1&&upper_bound(p[d].begin(), p[d].end(), r)- lower_bound(p[d].begin(), p[d].end(), l)==0)
        return false;
    return true;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,q,l,r,d;
        scanf("%d%d",&n,&q);
        for(int i=0;i<=100000;i++)
            p[i].clear();
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            shuru(i,x);
        }
        for(int i=1;i<=q;i++){
            scanf("%d%d%d",&l,&r,&d);
            if(panduan(d,l,r))
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值