小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. 【.NET 与树莓派】使用 GPIO 库

    上回老周在说准备工作的时候,提到过树莓派用金属盒散热的事情.有朋友会说,加了金属盒子接线不方便,就算用了"T"形板,毕竟是把导线延长了的.其实扩展板就是把原有的引脚引出(类似于延长 ...

  2. Linux学习笔记 | 常见错误之VMware启动linux后一直黑屏

    方法1: 宿主机(windows)管理员模式运行cmd 输入netsh winsock reset 然后重启电脑 netsh winsock reset命令,作用是重置 Winsock 目录.如果一台 ...

  3. Netty的简单Demo

    这个demo是通过网上下载: 使用maven构建的: 项目结构: pom.xml: <dependencies> <dependency> <groupId>io. ...

  4. Core3.1 微信v3 JSAPI支付

    1.前言 "小魏呀,这个微信支付还要多久?","快了快了老板,就等着最后一步了...","搞快点哈,就等着上线呢","...... ...

  5. STL_deque容器

    一.deque简介 deque是"double-ended queue"的缩写,和vector一样都是STL的容器,deque是双端数组,而vector是单端的. deque在接口 ...

  6. 邮箱发送API .Net

    调用QQ邮箱发送邮件接口,完成QQ邮箱发送邮件.步骤如下: 1.开启POP3/SMTP服务 2.点过之后会让你验证一下密保或者发送一条短信 3.验证过后会弹出一个开启POP3/SMTP服务的授权码,这 ...

  7. Redis持久化之父子进程与写时复制

    之所以将Linux底层的写时复制技术放在Redis篇幅下,是因为Redis进行RDB持久化时,BGSAVE(后面称之为"后台保存")会开辟一个子进程,将数据从内存写进磁盘,这儿我产 ...

  8. Maven 知识点总结以及解决jar报冲突的几种方法

    1.常见的命令 Compile Test Package Install Deploy Clean 2.坐标的书写规范 groupId 公司或组织域名的倒序 artifactId 项目名或模块名 ve ...

  9. 记一次Nginx反向代理500的排查记录

    今天公司项目遇到一个奇怪的问题,记录一下. 注: 数据已经过脱敏处理,未暴露公司具体的IP等数据. TLDR; 项目简单介绍 用 Vue + ElementUI 实现的后台项目(以下简称:a-proj ...

  10. go语言rpc学习

    rpc 就是  远程过程调用    指的是调用远端服务器上的程序的方法整个过程. rpc 理论 RPC技术在架构设计上有四部分组成,分别是:客户端.客户端存根.服务端.服务端存根. 客户端:服务调用发 ...