洛谷P1890 gcd区间 [2017年6月计划 数论09]
P1890 gcd区间
题目描述
给定一行n个正整数a[1]..a[n]。
m次询问,每次询问给定一个区间[L,R],输出a[L]..a[R]的最大公因数。
输入输出格式
输入格式:
第一行两个整数n,m。
第二行n个整数表示a[1]..a[n]。
以下m行,每行2个整数表示询问区间的左右端点。
保证输入数据合法。
输出格式:
共m行,每行表示一个询问的答案。
输入输出样例
输入样例#1:
5 3 4 12 3 6 7 1 3 2 3 5 5
输出样例#1:
1 3 7
说明
对于30%的数据,n <= 100, m <= 10
对于60%的数据,m <= 1000
对于100%的数据,1 <= n <= 1000,1 <= m <= 1,000,000
满足区间加法,询问远大于数据量,st表最快
#include <cstdio> #include <iostream> #include <cstring> const int MAXN = 1000 + 10; inline void read(long long& x) { x = 0;char ch = getchar();char c = ch; while(ch < '0' || ch > '9')c = ch, ch = getchar(); while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); if(c == '-')x = -x; } inline int min(long long a, long long b){return a > b ? a : b;} inline int max(long long a, long long b){return a > b ? b : a;} long long stlist[MAXN][30]; long long num[MAXN]; long long log2[MAXN]; long long pow2[MAXN]; long long n,m; inline int gcd(int a, int b) { if(a < b) { int tmp = a; a = b; b = tmp; } while(b) { int tmp = a % b; a = b; b = tmp; } return a; } void yuchuli() { int M = 0; while(pow2[M + 1] <= n)M ++; for(int i = 1;i <= M;i ++) { for(int j = n;j > 0;j --) { stlist[j][i] = stlist[j][i - 1]; if(j + pow2[i - 1] <= n)stlist[j][i] = gcd(stlist[j + pow2[i - 1]][i - 1], stlist[j][i]); } } } int stfind(int l, int r) { int M = 0; while(pow2[M + 1] <= (r - l + 1))M ++; return gcd(stlist[l][M], stlist[r - pow2[M] + 1][M]); } long long tmp1, tmp2; int main() { read(n);read(m); for(int i = 1;i <= n;i ++) read(stlist[i][0]); log2[0] = -1; for(int i = 1;i <= n;i ++) log2[i] = log2[i >> 1] + 1; pow2[0] = 1; for(int i = 1;i <= n;i ++) pow2[i] = pow2[i - 1] << 1; yuchuli(); for(int i = 1;i <= m;i ++) { read(tmp1);read(tmp2); printf("%d\n", stfind(tmp1, tmp2)); } return 0; }