HDU 5726 GCD

xiaoxiao2021-02-28  125

Description

给数组a1…an,Q个询问,每次询问取决[l, r],问gcd(al…ar)是多少,并且问总共有多少对l’,r’满足gcd(al’…ar’) == gcd(al…ar)

Algorithm

对于问题1,可以用线段树做,每个线段记录这个线段的gcd.但是会超时,所以需要用Sparse-Table做。 具体怎么做,参考《训练指南》P197~198 “RMQ问题”对于问题2,固定左端点的话,gcd(al…ar)是单调不增的。那么每次二分找到最大的一个R,gcd(ai…aR) == gcd(ai…aL),那么L…R这些都是相同的,用一个map存答案。 查询即可。

Code

#include <bits/stdc++.h> using namespace std; const int N(100000 + 9); int a[N], n; int d[N][100]; map<int, long long> ans; int mid(int l, int r) { return l+(r-l)/2; } void init() { for (int i(1); i <= n; i++) d[i][0] = a[i]; for (int j(1); (1<<j) <= n; j++) for (int i(1); i+(1<<j) <= n; i++) d[i][j] = __gcd(d[i][j-1], d[i+(1<<(j-1))][j-1]); } int query(int l, int r) { int k(0); while ((1<<(k+1)) <= r-l+1) k++; return __gcd(d[l][k], d[r-(1<<k)+1][k]); } void solve() { scanf("%d", &n); for (int i(1); i <= n; i++) scanf("%d", &a[i]); init(); ans.clear(); for (int i(1); i <= n; i++) { int L(i), R(0), g(a[i]); while (L <= n) { int l(L), r(n); while (l <= r) { int m(mid(l, r)); if (query(l, m) == g) l = m+1, R = m; else r = m-1; } ans[g] += R-L+1; L = R+1; R = L; g = __gcd(g, a[L]); } } int q; scanf("%d", &q); while (q--) { int l, r; scanf("%d%d", &l, &r); int t(query(l, r)); printf("%d %lld\n", t, ans[t]); } } int main() { int t; scanf("%d", &t); for (int i(1); i <= t; i++) { printf("Case #%d:\n", i); solve(); } }

阅读原文

转载请注明原文地址: https://www.6miu.com/read-68579.html

最新回复(0)