HDU 6287 口算训练

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

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

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

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

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

接下来mm行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000)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
前101010中共有质数不超过10000,所以开个动态二维数组,把第一个设为10000就好。vectorg[10000]
把每个数分解成有限个质因子相乘,然后存入一个数组,但存的方式是这样存的,比比如2是第0个质数,那包含质因子2的有那些数,以样例中输入来说,6 4 7 2 5 ,第一个数可以分成一个质因子2,那把1存入第零个质数中,g[0].push_back(1),
那第二个数可以分解为2个2,那就把2 2存入g【1】中
因为质因子分解是唯一的,那么只要判断d的每个质因子k个,在l,r范围内数中是不是至少能包含k个这样的质因子,如果有一个不满足的,就不能整除
由于一个数大于x大于sqrt(x)的质因子最多只有一个,所以这个要单独考虑,可以省下不少时间。
自己记录一下知识点
upper_bound(p.begin(),p.end(), r),即可返回数组p中p[0]开始第一个大于r的地址,如果找不到,就返回end的地址。
详见代码

// ConsoleApplication143.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//#include "pch.h"
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<math.h>
#include<iomanip>
#include<vector>

using namespace std;

#define pb push_back
#define sz(s) ((int)s.size())
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef pair<int, int> pii;
vector<int>p;
bool isp[101010];
void pri() {
	for (int i = 2; i < 101010; i++) {
		if (!isp[i])
		{
			p.pb(i);
		}
		else continue;
			for (int j = 2; j*i < 101010;j++) {
			isp[j*i] = 1;
					}
	}
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T, n, m;
	cin >> T;
		vector<int>g[10000];
		pri();
	while (T--)
	{
		for (int i = 0; i < sz(p); i++)
			g[i].clear();
		int x;
		cin >> n >> m;
		for (int i = 1; i <= n; i++)
		{
			cin >> x;
			for (int j = 0; j < sz(p) && p[j] * p[j] <= x; j++)
			{
				if (x%p[j] == 0)
					while (x%p[j] == 0)
						g[j].pb(i), x /= p[j];
			}
			if (x > 1)
				g[upper_bound(all(p), x-1) - p.begin()].pb(i);
		}
		int l, r, d;	
		while (m--)
		{
			cin >> l >> r >> d;
			int temp = 0;
			for (int i = 0; i < sz(p) && p[i] * p[i] <= d; i++)
			{
				if (d%p[i] == 0)
				{
					int ant = 0;
					while (d%p[i] == 0)
						ant++, d /= p[i];
					int sum = upper_bound(all(g[i]), r) - upper_bound(all(g[i]), l - 1);
					if (sum < ant) {
						temp = 1; break;
					}
				}
			}
			if (!temp&&d > 1)
			{
				int v = upper_bound(all(p), d-1) - p.begin();
				int u = upper_bound(all(g[v]), r) - upper_bound(all(g[v]), l - 1);
				if (u < 1)temp = 1;
			}
			if (temp)cout << "No" << endl;
			else cout << "Yes" << endl;
		}
	}
}在这里插入代码片
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值