小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为n的正整数序列a1,a2,...,an,要求小T抛出m个问题以训练他的口算能力。
每个问题给出三个正整数l,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×ar是不是d
每组数据第一行包含两个正整数n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含n个正整数a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来m行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。 Output 对于每个问题输出一行,若是倍数,输出Yes,否则输出No。 Sample Input
每个问题给出三个正整数l,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×ar是不是d
的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input 第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。 小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含n个正整数a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来m行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。 Output 对于每个问题输出一行,若是倍数,输出Yes,否则输出No。 Sample Input
1 5 4 6 4 7 2 5 1 2 24 1 3 18 2 5 17 3 5 35Sample 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;
}