题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6287
题目:
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 177 Accepted Submission(s): 41
Problem Description
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为
的正整数序列
,要求小T抛出
个问题以训练他的口算能力。
每个问题给出三个正整数 ,小Q需要通过口算快速判断 是不是 的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
每个问题给出三个正整数 ,小Q需要通过口算快速判断 是不是 的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input
第一行包含一个正整数
,表示测试数据的组数。
每组数据第一行包含两个正整数 ,分别表示序列长度以及问题个数。
第二行包含 个正整数 ,表示序列中的每个数。
接下来 行,每行三个正整数 ,表示每个问题。
每组数据第一行包含两个正整数 ,分别表示序列长度以及问题个数。
第二行包含 个正整数 ,表示序列中的每个数。
接下来 行,每行三个正整数 ,表示每个问题。
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
思路:如博客题目所言,唯一分解定理+二分。首先将所有的a进行素数分解,然后用一个vector记录这个素数出现的位置(如x % i == 0, 此时x 是第8位数,那么p[i].push_back(8)),然后二分从d分解出来的素数在该区间内出现总次数是否大于它在d中的次数。
代码实现如下:
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 1e5 + 7; 7 int t, n, m, l, r, d, x; 8 9 vector<int> G[maxn]; 10 11 int check(int l, int r, int x) { 12 return upper_bound(G[x].begin(), G[x].end(), r) - lower_bound(G[x].begin(), G[x].end(), l); 13 } 14 15 bool slove(int l, int r, int x) { 16 for(int i = 2; i * i <= x; i++) { 17 int cnt = 0; 18 if(x % i == 0) { 19 while(x % i == 0) { 20 cnt++; 21 x /= i; 22 } 23 if(cnt > check(l, r, i)) { 24 return false; 25 } 26 } 27 } 28 if(x > 1) { 29 if(check(l, r, x) < 1) { 30 return false; 31 } 32 } 33 return true; 34 } 35 36 int main() { 37 scanf("%d", &t); 38 while(t--) { 39 scanf("%d%d", &n, &m); 40 for(int i = 0; i < maxn; i++) { 41 G[i].clear(); 42 } 43 for(int i = 1; i <= n; i++) { 44 scanf("%d", &x); 45 for(int j = 2; j * j <= x; j++) { 46 if(x % j == 0) { 47 while(x % j == 0) { 48 G[j].push_back(i); 49 x /= j; 50 } 51 } 52 } 53 if(x > 1) { 54 G[x].push_back(i); 55 } 56 } 57 while(m--) { 58 scanf("%d%d%d", &l, &r, &d); 59 printf("%s\n", slove(l, r, d) ? "Yes" : "No"); 60 } 61 } 62 }