HDU6287 口算训练(唯一分解定理+二分)

口算训练

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


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
 
 
15 46 4 7 2 51 2 241 3 182 5 173 5 35
 

Sample Output
 
 
YesNoNoYes

 

题意:中文题目

思路:

    1)运用:

            1.vector    (动态数组)   

            2.upper_bound    (返回小于等于key的最后一个元素的后一个元素)

            3.lower_bound    (返回大于等于key的第一元素)

            4.任何大于1的自然数,都可以唯一分解成有限个质数的乘积(唯一分解定理)

    2)步骤:

            1.将所给数组进行质因数分解,并且把数组标存入G[i]中。

            

//id原数组的下标,x原数组的值。eg:a[4]={2,3,4,5}    prim(0,2) 
void prim(int id,int x){
	for(int i=2 ; i*i<=x ;i++){
		while(x%i==0){
			G[i].push_back(id);
			x/=i;
		}
	}
	if(x>1){
		G[x].push_back(id);
	}
}

            2.将查询的P也进行质因数分解,然后将每个质因数的个数与原数组区间对应质因数的个数比较

           

/*eg:
	  a		b
   	 30             6    
       2,3,5           2,3
	
	 36             6
       2,2,3,3         2,3
   
   只要b全部的质因数都出现在a中,且相应质因数小于等于a中的,
   a就是b的倍数 
*/

            3.注意,在处理质因数时(p函数),可能6/2=3,接着3没被处理。


//质因数分解+二分答案 

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e5+10;
vector<int> G[maxn];

//id原数组的下标,x原数组的值。eg:a[4]={2,3,4,5}    prim(0,2) 
void prim(int id,int x){
    for(int i=2 ; i*i<=x ;i++){
        while(x%i==0){
            G[i].push_back(id);
            x/=i;
        }
    }
    if(x>1){
        G[x].push_back(id);
    }
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        for(int i=0;i<maxn;i++) G[i].clear();
        int n,m;
        int x;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            prim(i,x);
        }
        while(m--){
            int l,r,p,flag=0,cnt;
            scanf("%d%d%d",&l,&r,&p);
            for(int i=2;i*i<=p;i++){
                cnt=0;
                while(p%i==0){
                    cnt++;
                    p/=i;
                }
                if(cnt){
                    int pos = upper_bound(G[i].begin(),G[i].end(),r)-lower_bound(G[i].begin(),G[i].end(),l);
                    if(pos<cnt){
                        flag=1;
                    }
                }                
            }
            if(p>1){
                int pos = upper_bound(G[p].begin(),G[p].end(),r)-lower_bound(G[p].begin(),G[p].end(),l);
                if(!pos){
                    flag=1;
                }
            }
            if(flag) puts("No");
            else puts("Yes");
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值