爱思创 181021 gcd区间 题解
思路
这一道题我们要先知道什么是 最大公因数 (gcd)。
最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。
在程序中可以直接调用函数: __gcd()
不过我们还是用辗转相除法手写一个递归版吧。
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
求多个数的最大公因数一直gcd就行,比如 \(gcd(a, b, c, d) = gcd(gcd(gcd(a, b), c), d)\)
现在可以求最大公因数了,开始想其他部分
这一题要求很多个区间的最大公因数,是一道 RMQ 问题 的变种,正常枚举肯定不行,需要优化。我们可以用 ST表 来做
ST表类似动态规划(dp),基于 倍增 思想,它能够使线性的处理转化为对数级的处理,大大地优化时间复杂度。
st[i][j]意为从第 \(i\) 位开始的 \(2^j\) 位的最大公因数
状态转移方程式为
st[i][j] = gcd(st[i][j - 1]/*左区间*/, st[i + (1 << (j - 1))][j - 1]/*右区间*/);
//两个区间用gcd()合并
输出时
int len = r - l + 1;//区间总长
int k = log2(len);
printf("%d\n", gcd(st[l][k]/*左覆盖区间*/, st[r - (1 << k) + 1/*右区间-长度+1为右覆盖区间起点*/][k]/*右覆盖区间*/)/*整体gcd()*/);
整体代码(上面没讲的细节看注释)
#include<bits/stdc++.h>
using namespace std;
int st[1005][15/*大于log2(1000)即可*/];
int a[1005];
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++) st[i][0] = a[i];
for(int j = 1; (1 << j) <= n; j ++)//外层循环的是j(长度),不是i(位置)
{
for(int i = 1; i + (1 << (j - 1))/*处理溢出*/ <= n; i ++)
{
st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
while(m --)
{
int l, r;
scanf("%d %d", &l, &r);
int len = r - l + 1;
int k = log2(len);
printf("%d\n", gcd(st[l][k], st[r - (1 << k) + 1][k]));
}
return 0;
}
hello, I'm yuzihang, if you need to copy this, please quote this url: https://www.cnblogs.com/yuzihang/articles/16947292.html

浙公网安备 33010602011771号