小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

思路参考链接:https://blog.csdn.net/wjmwsgj/article/details/80519183

对于一个数(k)是不是d的倍数这类问题,我们可以对这两个数分解质因数,之后看看k的质因数和d的质因数之间的关系,如果满足对于d的每一个质因数个数,在k中都有出现过,且k的出现次数要大于等于d的出现次数,这个就是满足的,举个例子,36 和 6 ,36的质因数有 2,2,3,3,6的质因数有 2,3,其中36中2出现的次数大于了6中2出现的次数,36中3出现的次数大于了6中3出现的次数,故36是6的倍数。

那么对于这道题,我们需要做的就是先将这n个数分解质因数,对于区间问题我们要怎么解决呢?我们把质因数出现的位置给存下来,比如说我们现在在第3个数,a[3] = 8 ,那么我们开一个vector w[2]里加入 3,3,3,3,(相当于w[2]里面记录的是2这个质因子是下标为2这个数的因子)之后,之后比如说我们现在要查询l,r的区间是不是d的倍数,我们将d分解质因数之后用二分去查询我们当前的区间里有没有这个值就好了。

刚开始用的质因子分解方法复杂度太大,导致TLE

 1 const int maxn=100005;
2 vector<int>w[maxn];
3 int maxx=0;
4 bool isprim(int x)
5 {
6 for(int i=2; i<=sqrt(x); ++i)
7 {
8 if(x%i==0) return 0;
9 }
10 return 1;
11 }
12 void digui(int x,int id)
13 {
14 int temp=sqrt(x);
15 if(isprim(x))
16 w[x].push_back(id),maxx=max(maxx,x);
17 else
18 {
19 for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子
20 {
21 if(x%i==0)
22 {
23 digui(i,id);
24 digui(x/i,id);
25 }
26 }
27 }
28 }

TLE全部代码:

 1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 #include<algorithm>
5 #include<math.h>
6 #include<vector>
7 using namespace std;
8 typedef long long ll;
9 const int maxn=100005;
10 vector<int>w[maxn];
11 int maxx=0;
12 bool isprim(int x)
13 {
14 for(int i=2; i<=sqrt(x); ++i)
15 {
16 if(x%i==0) return 0;
17 }
18 return 1;
19 }
20 void digui(int x,int id)
21 {
22 int temp=sqrt(x);
23 if(isprim(x))
24 w[x].push_back(id),maxx=max(maxx,x);
25 else
26 {
27 for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子
28 {
29 if(x%i==0)
30 {
31 digui(i,id);
32 digui(x/i,id);
33 }
34 }
35 }
36 }
37 int main()
38 {
39 int t;
40 scanf("%d",&t);
41 while(t--)
42 {
43 maxx=0;
44 int n,m;
45 scanf("%d%d",&n,&m);
46 for(int i=0;i<maxn;i++)
47 w[i].clear();
48 for(int i=0;i<n;++i)
49 {
50 int x;
51 scanf("%d",&x);
52 digui(x,i);
53 }
54 // for(int i=0;i<maxx;i++)
55 // sort(w,w+w[i].size());
56 while(m--)
57 {
58 int flag=0,l,r,d;
59 scanf("%d%d%d",&l,&r,&d);
60 l--,r--;
61 for(int i=2;i<=sqrt(d);++i)
62 {
63 int num=0;
64 while(d%i==0)
65 d/=i,num++;
66 if(num)
67 {
68 int pos=upper_bound(w[i].begin(),w[i].end(),r)-lower_bound(w[i].begin() , w[i].end(),l);
69 if(pos < num) //如果小于我们现在需要的,就说明不行。
70 {
71 flag=1;
72 break;
73 }
74 }
75 }
76 if(d>1) //同理
77 {
78 int pos=upper_bound(w[d].begin(),w[d].end(),r)-lower_bound(w[d].begin() , w[d].end(),l);
79 if(pos==0) flag=1;
80 }
81 if(flag)
82 {
83 printf("No\n");
84 }
85 else
86 {
87 printf("Yes\n");
88 }
89 }
90 }
91 return 0;
92 }

实际上不需要用isprim来判断某个数是不是素数

看下面一种方法:

 1 const int maxn=100005;
2 vector<int>w[maxn];
3 int maxx=0;
4 void resolve(int x,int id)
5 {
6 for(int i = 2 ; i * i <= x ; i++) // 这里的i最大是313
7 {
8 while(x % i == 0) //一直除的话就不会遇到i是合数的情况
9 {
10 w[i].push_back(id);
11 x = x/i;
12 }
13 }
14 if(x>1) // 这里有一个问题就是 我sqrt(maxn)里的最大的质数其实是313,那么我来了一个2 * 313的时候,我们找到的质因数只有2 ,所以当他没有到1的时候说明我们没有完
15 {
16 w[x].push_back(id); // 需要在搞一下
17 }
18 }

正确代码:

  1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 #include<algorithm>
5 #include<math.h>
6 #include<vector>
7 using namespace std;
8 typedef long long ll;
9 const int maxn=100005;
10 vector<int>w[maxn];
11 int maxx=0;
12 void resolve(int x,int id)
13 {
14 for(int i = 2 ; i * i <= x ; i++) // 这里的i最大是313
15 {
16 while(x % i == 0) //一直除的话就不会遇到i是合数的情况
17 {
18 w[i].push_back(id);
19 x = x/i;
20 }
21 }
22 if(x>1) // 这里有一个问题就是 我sqrt(maxn)里的最大的质数其实是313,那么我来了一个2 * 313的时候,我们找到的质因数只有2 ,所以当他没有到1的时候说明我们没有完
23 {
24 w[x].push_back(id); // 需要在搞一下
25 }
26 }
27 /*这一种质因数分解太耗时了*/
28 //bool isprim(int x)
29 //{
30 // for(int i=2; i<=sqrt(x); ++i)
31 // {
32 // if(x%i==0) return 0;
33 // }
34 // return 1;
35 //}
36 //void digui(int x,int id)
37 //{
38 // int temp=sqrt(x);
39 // if(isprim(x))
40 // w[x].push_back(id),maxx=max(maxx,x);
41 // else
42 // {
43 // for(int i=2; i<=temp; ++i) //这个for循环作用就是找一个x的因子
44 // {
45 // if(x%i==0)
46 // {
47 // digui(i,id);
48 // digui(x/i,id);
49 // }
50 // }
51 // }
52 //}
53 int main()
54 {
55 int t;
56 scanf("%d",&t);
57 while(t--)
58 {
59 maxx=0;
60 int n,m;
61 scanf("%d%d",&n,&m);
62 for(int i=0;i<maxn;i++)
63 w[i].clear();
64 for(int i=0;i<n;++i)
65 {
66 int x;
67 scanf("%d",&x);
68 //digui(x,i);
69 resolve(x,i);
70 }
71 // for(int i=0;i<maxx;i++)
72 // sort(w,w+w[i].size());
73 while(m--)
74 {
75 int flag=0,l,r,d;
76 scanf("%d%d%d",&l,&r,&d);
77 l--,r--;
78 for(int i=2;i<=sqrt(d);++i)
79 {
80 int num=0;
81 while(d%i==0)
82 d/=i,num++;
83 if(num)
84 {
85 //upper_bound是找到大于r的
86 //low_bound是找到大于等于l的
87 int pos=upper_bound(w[i].begin(),w[i].end(),r)-lower_bound(w[i].begin() , w[i].end(),l);
88 if(pos < num) //如果小于我们现在需要的,就说明不行。
89 {
90 flag=1;
91 break;
92 }
93 }
94 }
95 if(d>1) //同理
96 {
97 int pos=upper_bound(w[d].begin(),w[d].end(),r)-lower_bound(w[d].begin() , w[d].end(),l);
98 if(pos==0) flag=1;
99 }
100 if(flag)
101 {
102 printf("No\n");
103 }
104 else
105 {
106 printf("Yes\n");
107 }
108 }
109 }
110 return 0;
111 }

HDU - 6287 口算训练 二分+质因数分解的更多相关文章

  1. hdu 6287 口算训练

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

  2. [BZOJ5358]/[HDU6287]口算训练

    [BZOJ5358]/[HDU6287]口算训练 题目大意: 给定一个长度为\(n(n\le10^5)\)的正整数序列\(a_{1\sim n}\),\(m(m\le10^5)\)次询问.每次询问给出 ...

  3. C# WinForm动态控件实例:口算训练

    昨天晚上回寝室看到室友正在被一个C#课的作业苦恼,作业的内容是编写一个口算训练程序,能够实现随意添加题目数量.于是,喜欢写C#的我就决定解救一下他们. 创建动态控件 既然要动态添加,那就必须使用动态控 ...

  4. [Bzoj5358][Lydsy1805月赛]口算训练(预处理+动态开点线段树)

    5358: [Lydsy1805月赛]口算训练 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 318  Solved: 105[Submit][Stat ...

  5. 2018 CCPC 女生赛 hdoj6287 口算训练

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=6287 Summarize: 1.分解质因数: 2.二分查找函数lower_bound与upper_bo ...

  6. [Lydsy1805月赛]口算训练 BZOJ5358

    分析: 没想到这道题还能二分查找... 这题主席树的话,裸的很显然...我们将每一个数分解质因数,之后建一个可持久化权值线段树维护[L,R]区间内的每一种质因子的个数,分解质因数的话,可以选择用线筛, ...

  7. WPF简单的口算案例

    前几天在博客园,看到有博友利用Winform做了一个口算案例,于是我想把它移植在WPF程序中.Winform程序:http://www.cnblogs.com/ImYZF/p/3345452.html ...

  8. POJ 1845 Sumdiv#质因数分解+二分

    题目链接:http://poj.org/problem?id=1845 关于质因数分解,模板见:http://www.cnblogs.com/atmacmer/p/5285810.html 二分法思想 ...

  9. 【(阶乘的质因数分解)算组合数】【TOJ4111】【Binomial efficient】

    n<=10^6 m<=10^6 p=2^32 用unsigned int 可以避免取模 我写的SB超时 阶乘分解代码 #include <cstdio> #include &l ...

随机推荐

  1. Jmeter(三十五) - 从入门到精通进阶篇 - 关联(详解教程)

    1.简介 上一篇中介绍了如果想要同时发送多条请求,那么怎样才能让每条数据某些请求参数改变呢.这就用到了jMeter参数化.在实际测试场景中,我们往往还有这样的需求,登录后服务器响应的token作为下次 ...

  2. HAProxy-1.8.20 根据后缀名转发到后端服务器

    global maxconn 100000 chroot /data/soft/haproxy stats socket /var/lib/haproxy/haproxy.sock mode 600 ...

  3. SpringBoot WebSocket技术

    最近看了Spring in Action,了解了一下WebSocket和Stomp协议相关技术,并搭建了一个项目.网上的例子不完整或者描述不清,所以自己记录一下以作备忘. 一.配置 Spring Bo ...

  4. Vitis下载安装尝试

    Vitis下载安装记录 一.下载安装 文章目录 一.下载安装 提示:以下是本篇文章正文内容,下面案例可供参考 一.下载安装 首先本次下载主要使用的是linux系统,所以我们先看一下Vitis支持的li ...

  5. SAP密码策略挺有意思

    很多系统管理员可能都知道通过RZ10可以配置SAP的密码策略.例如:密码里包含的大小写字符.数字.特殊字符.密码长度.密码不能和前多少次的密码相同.不能和之前的密码有多少位相似等但是你知道吗?其实还有 ...

  6. LuoguP5075 [JSOI2012]分零食

    题意 有\(A\)个人,\(m\)个糖,你可以选择一个\(k\),使第\(1\)$k$个人每个人至少得到一个糖,并且第$k+1$\(A\)个人都得不到糖.\(m\)个糖必须给完.对于每个方案都有一个欢 ...

  7. pytest:通过scope控制fixture的作用范围

    一.fixture里面有个参数scope,通过scope可以控制fixture的作用范围,根据作用范围大小划分:session>module>class>function,具体作用范 ...

  8. 支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型

    支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型 原创 杨翊(席翁) 阿里巴巴云原生 2020-12-28    

  9. Certbot CA 证书 https

    certbot (base) a@test:~# certbot --help - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...

  10. SRE SLO On-Call 流程机制 系统稳定性

    开篇词|SRE是解决系统稳定性问题的灵丹妙药吗? https://time.geekbang.org/column/article/212686 这两年,近距离地接触了很多不同类型.不同规模的企业 I ...