题目描述
给定一行n个正整数a[1]..a[n]。
m次询问,每次询问给定一个区间[L,R],输出a[L]..a[R]的最大公因数。
输入输出格式
输入格式:
第一行两个整数n,m。
第二行n个整数表示a[1]..a[n]。
以下m行,每行2个整数表示询问区间的左右端点。
保证输入数据合法。
输出格式:
共m行,每行表示一个询问的答案。
输入输出样例
输入样例#1:
复制代码
1
2
3
4
55 3 4 12 3 6 7 1 3 2 3 5 5
输出样例#1:
复制代码
1
2
31 3 7
说明
对于30%的数据,n <= 100, m <= 10
对于60%的数据,m <= 1000
对于100%的数据,1 <= n <= 1000,1 <= m <= 1,000,000
复制代码
1
20 < 数字大小 <= 1,000,000,000
题目地址: https://www.luogu.org/problemnew/show/P1890
个人思路:
- 一开始打了个枚举获取答案的代码,虽然开了inline,并使用了scanf,但还是TLE了最后两个点.
- 之后又尝试使用一个data[]数组,记忆化已经gcd得到的答案,仍然TLE,
- 想了一下,只好看题解.题解的方法是预处理,然后O(1)查询.
- 然后就自己思考了一下,之前也想过预处理,但是感觉复杂度可能太高了.
- 但是题解中的预处理使用了gcd的一个传递性.假设我们要预处理的是a[i],则预处理存储数组data[i][j]=gcd(data[i][j-1])(因为j代表区间长度,代表起始点.然后通过最大公约数的性质即可求出答案)
- 再思考一下时间复杂度,大约为O(
),又因为n的范围够小,所以这个时间复杂度可以接受.
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include<cstdio> #include<iostream> using namespace std; int a[1000],data[1005][1005]; inline int gcd(int a,int b){ if(a<b)swap(a,b);; if(b==0)return a; return gcd(b,a%b); } int main(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++){ data[i][j]=gcd(data[i][j-1],a[j]); } } for(int i=1;i<=m;i++){ int ta,tb; scanf("%d%d",&ta,&tb); printf("%dn",data[ta][tb]); } return 0; }
最后
以上就是缓慢面包最近收集整理的关于C++ P1890 gcd区间的全部内容,更多相关C++内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复