口算训练 (质数的分解+一个不知道名的算法)

本文介绍了一种高效判断区间乘积是否为特定数倍数的方法。通过质因数分解和动态数组记录每个数的质因数,在不直接计算区间乘积的前提下,利用二分查找确定指定区间内各质因数的总数量是否满足条件。适用于训练快速口算能力和算法竞赛。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小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

思路:如果直接从l到r进行取余计算会超时。

            然后参考了其他博客:对每一个数进行质因子的分解,并且满足唯一分解定理。

            为了防止爆空间使用动态数组vector<int> maze[i]进行储存,其中动态数组的下标表示质因子,

        数组中储存的数表示,A1~An之间具有这个质因子的下标。然后二分从d分解出来的素数在

            该区间内出现总次数是否大于它在d中的次数。

代码实现如下:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> maze[100010];

int panduan(int l, int r, int x){
     return upper_bound(maze[x].begin(), maze[x].end(), r) - lower_bound(maze[x].begin(), maze[x].end(), l);
}    //不懂这个原理,结果就是l~r之间每个数因子是x的总个数
int panduan1(int l,int r,int x)
{
    int i,k,countt;
    k=x;
    for(i=2;i*i<=k;i++){
        countt=0;
        if(x%i==0){
            while(x%i==0){
                countt++;  //countt储存素数是i时的,x中的是i的因子的个数
                x=x/i;
            }
            if(countt>panduan(l,r,i))
                return 0;

        }
    }

    if(x>1){
        if(panduan(l,r,x)<1)
            return 0;
    }

    return 1;
}
int main()
{
    int f,i,j,n,m,x,flag,l,r,d;

    scanf("%d",&f);
    while(f--){
        scanf("%d %d",&n,&m);


         for(i = 0; i < 100010; i++) {
             maze[i].clear();
         }   //必须对动态数组进行清零处理,不然WA

        for(i=1;i<=n;i++){
            scanf("%d",&x);
            for(j=2;j*j<=x;j++){  //通过这种质因子排查法,不必进行素数的筛选
                if(x%j==0){
                    while(x%j==0){
                        maze[j].push_back(i);
                        x=x/j;
                    }
                }
            }
            if(x>1)
                maze[x].push_back(i);  //最后剩余的素数不要忘记
        }


        while(m--){

            scanf("%d %d %d",&l,&r,&d);

            flag=panduan1(l,r,d);

            if(flag==1)
                printf("Yes\n");
            else
                printf("No\n");
        }

    }

    return 0;
}

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值