2018 ccpc女生赛 口算训练 (二分 + 唯一分解定理)

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

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

小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input第一行包含一个正整数 T(1T10)T(1≤T≤10),表示测试数据的组数。 

每组数据第一行包含两个正整数 n,m(1n,m100000)n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。 

第二行包含 nn个正整数 a1,a2,...,an(1ai100000)a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。 

接下来 mm行,每行三个正整数 l,r,d(1lrn,1d100000)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


先用vector记录下每个因子出现的位置。vector里存的是含有i这个因子的下标。

查找l到r里因子个数时用upper_bound() - lower_bound()就可以。 

#include<bits/stdc++.h>
using namespace std;
vector<int> a[100005];
int T, n, m;
void init(int x, int Index){
	for(int i = 2; i * i <= x; i++){
		if(x % i == 0){
			while(x % i == 0){
				x /= i;
				a[i].push_back(Index);
			}
		}
	}
	if(x > 1)
		a[x].push_back(Index);
}

int query(int l, int r, int x){
	return upper_bound(a[x].begin(), a[x].end(), r) - lower_bound(a[x].begin(), a[x].end(), l);
}

int judge(int l, int r, int x){
	for(int i = 2; i * i <= x; i++){
		if(x % i == 0){
			int t = 0;
			while(x % i == 0){
				x /= i;
				t++;
			}
			int c = query(l, r, i);
			if(t > c)
				return 0;
		}
	}
	if(x > 1 && query(l, r, x) < 1)
		return 0;
	return 1;
}

int main()
{
	scanf("%d", &T);
	while(T--){
		for(int i = 0; i < 100005; i++)
			a[i].clear();
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; i++){
			int x;
			scanf("%d", &x);
			init(x, i);
		}
		for(int i = 0; i < m; i++){
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			int flag = judge(l, r, d);
			if(flag)
				printf("Yes\n");
			else
				printf("No\n");
		}
	}
	return 0;
}




猜你喜欢

转载自blog.csdn.net/sxh759151483/article/details/80632668
今日推荐