HUD—6287,口算训练,思维,素因子分解,lower_bound, upper_bound

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


 

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

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

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

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

每组数据第一行包含两个正整数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 35
 

Sample Output
 
 
Yes
No
No
Yes

解析:

我们可以将所有数字进行素因子分解,如 6 4 他们的乘积可以分解为2^3*3^1,而 24 同样可以备份分解为 2^3*3^1 显然,当询问的数字分解的素因子均存在与区间乘积的分解后的因子中,且区间乘积分解的任意因子的次幂均不小于询问的数字分解的素因子的次幂时,区间乘积就一定被所询问的数字整除

但这里有一个难点:我们如何存储分解出来的素因子及其次幂,同时还能方便后续的查找呢?
这里提供一个方法:vector<int>G[N]
G[i] 内的信息表示素因子 i 出现的位置
如: 6 4
则 G[2]={1,2,2}   //素因子 1 出现在第一个位置,由于位置只有一个 1 个,所以在位置1只出现了一次;素因子 2 出现在第一个位置,由于位置只有一个 2 个,所以在位置 2 只出现了两次
   G[3]={1}          //素因子 3 出现在第一个位置,由于位置只有一个 1 个,所以在位置1只出现了一次

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
int n,m;
int a[N];
int l, r, d;
vector<int>G[N];

void F(int t, int index) {
	for (int i = 2; i * i <= t; i++) {
		while (t % i == 0) {
			G[i].push_back(index);
			t /= i;
		}
	}
	if (t>1) {
		G[t].push_back(index);
	}
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		for (int i = 1; i < N; i++)G[i].clear();
		for (int i = 1,t; i <= n; i++) {
			scanf("%d", &t);
			F(t,i);
		}
		while (m--) {
			int flg = 0,cnt=0;
			scanf("%d%d%d", &l, &r, &d);
			for (int i = 2; i * i <= d; i++) {
				cnt = 0;
				while (d % i == 0) {
					d /= i;
					cnt++;
				}
				if (cnt) {//千万注意,不能少这个判断,否则会多出很多无意义的运行,回爆时间
					//lower_bound 返回一个迭代器,指向序列中不小于给定值的第一个元素。
					//upper_bound 返回一个迭代器,指向序列中大于给定值的第一个元素。
					int pp = upper_bound(G[i].begin(), G[i].end(), r) - lower_bound(G[i].begin(), G[i].end(), l);
					if (pp < cnt) {
						flg = 1;
						break;
					}
				}
			}
			if (d > 1) {
				int pp = upper_bound(G[d].begin(), G[d].end(), r) - lower_bound(G[d].begin(), G[d].end(), l);
				if (!pp) {
					flg = 1;
				}
			}
			if (flg) {
				printf("No\n");
			}
			else {
				printf("Yes\n");
			}
		}
	}
	return 0;
}

posted @ 2023-10-17 21:08  Landnig_on_Mars  阅读(4)  评论(0编辑  收藏  举报  来源