题目链接:点击打开链接
题意:给你一个n的全排列, q个操作, 每个操作是一个区间,要求求出这个区间中任意两个数的gcd的最大值。
思路:一个数是两个数的公约数, 等价于一个数可以被两个整数同时整除。 所以我们可以算出每一个数的所有约数, 然后求一个区间中被超过两个数整除的数中的最大值即可。
维护区间最大值, 我们可以用线段树来维护。 因为我们难以同时维护一个区间, 所以我们离线处理, 按照r排序, 那么每次如果当前数的一个约数曾经出现过, 就在之前出现的点加入线段树, 每次顺便查询即可。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; // & 0x7FFFFFFF const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 50000 + 10; int T,n,m,maxv[maxn<<2],a[maxn],pre[maxn],ans[maxn]; struct node { int id, l, r; node(int id=0, int l=0, int r=0):id(id), l(l), r(r) {} bool operator < (const node& rhs) const { return r < rhs.r; } }op[maxn]; void pushup(int o) { maxv[o] = max(maxv[o<<1], maxv[o<<1|1]); } void build(int l, int r, int o) { int m = (l + r) >> 1; maxv[o] = 0; if(l == r) return ; build(l, m, o<<1); build(m+1, r, o<<1|1); } void update(int L, int R, int v, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { maxv[o] = max(maxv[o], v); return ; } if(L <= m) update(L, R, v, l, m, o<<1); if(m < R) update(L, R, v, m+1, r, o<<1|1); pushup(o); } int query(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { return maxv[o]; } int ans = 0; if(L <= m) ans = max(ans, query(L, R, l, m, o<<1)); if(m < R) ans = max(ans, query(L, R, m+1, r, o<<1|1)); pushup(o); return ans; } int q, r, l; int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } scanf("%d",&q); for(int i=0;i<q;i++) { scanf("%d%d",&op[i].l,&op[i].r); op[i].id = i; } memset(pre, -1, sizeof(pre)); sort(op, op + q); int cnt = 0; build(1, n, 1); for(int i=1;i<=n;i++) { for(int j=1;j*j<=a[i];j++) { if(a[i] % j != 0) continue; if(pre[j] != -1) { update(pre[j], pre[j], j, 1, n, 1); } if(j*j != a[i] && pre[a[i]/j] != -1) { update(pre[a[i]/j], pre[a[i]/j], a[i]/j, 1, n, 1); } pre[j] = i; pre[a[i]/j] = i; } while(cnt < q && op[cnt].r == i) { ans[op[cnt].id] = query(op[cnt].l, i, 1, n, 1); ++cnt; } } for(int i=0;i<q;i++) { printf("%d\n",ans[i]); } } return 0; }