小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. JavaFX之班级未交作业统计

    前言 最近转移了系统平台,用上了Ubuntu1804版本系统,原来用C#写的Windows窗体软件也不能用了,而且自己在班级上每周都需要收作业,所以写了这个软件.这篇博客主要记录这个JavaFX应用的 ...

  2. ElasticJob 快速上手

    1.  ElasticJob 是什么 ElasticJob 是一个分布式调度解决方案,由两个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成. Elasti ...

  3. 【Oracle】常见等待事件处理

    1.查看数据库中需要关注的等待事件: select sw.seq#,sw.sid||','||s.serial# sids,s.username,sw.event,sw.P1,sw.p2,sw.p3, ...

  4. 查看pod日志无法查看的解决方式

    查看pod日志 [root@k8s-master1 ~]# kubectl logs nginx-7cdbd8cdc9-2qrcw Error from server (Forbidden): For ...

  5. 使用modify修改内表

    modify修改内表,有这样一种方式,MODIFY TABLE itab FROM wa [TRANSPORTING ..]. 然后这里的内表itab是有条件的,这个itab必须要有table key ...

  6. postgresql-12编译安装

    1 准备环境 修改yum源 mkdir -p /etc/yum.bak mv /etc/yum.repos.d/* /etc/yum.bak/ &&\ curl -o /etc/yum ...

  7. 第一章:起步(python环境搭建)

    Python 环境搭建 学习python的第一步,就是要学习python开发环境的配置,在配置好python开发环境后,你需要再安装一款比较趁手的编辑器,事实上,python解释器本身就可以进行一些编 ...

  8. python_mmdt:一种基于敏感哈希生成特征向量的python库(一)

    概述 python_mmdt是一种基于敏感哈希的特征向量生成工具.核心算法使用C实现,提高程序执行效率.同时使用python进行封装,方便研究人员使用. 本篇幅主要介绍涉及的相关基本内容与使用,相关内 ...

  9. Windows环境下搭建FTP服务器

    Windows主机建立FTP服务器 第一步:启用对应的Windows功能 控制面板 选择启用或关闭Windows功能 勾选FTP服务器和Web管理工具 可能出现的问题 系统提示无法安装IIS和FTP服 ...

  10. 一键测试VPS到国内速度脚本 SuperBench.sh,以及一键验收云主机脚本

    我们买国外VPS服务器测试网络通常会用到speedtest,speedtest默认是测试到最近的节点,那么到国内速度如何呢?虽然可以指定服务器编号,但是一个个测试还是比较麻烦的,这里推荐一个脚本整合了 ...