hdu 5726, 2016多校1 - D,st表+二分
解:本来是个瓜题,结果我看错题以为是问子区间内有多少种情况了= =。如果是对于原来的整个区间,利用gcd只有log个的性质二分+st表O(1)维护查询即可。
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <map> using namespace std; #define MAXN 111111 #define ABS(x) ((x)<0?(-(x)):(x)) #define LL long long const double LIM = 1e30; const double EPS = 1e-9; map <int, LL > mp; int a[MAXN], n, st[MAXN][20]; int query(int l, int r) { int k = (int)log2((double)(r-l+1)); return __gcd(st[l][k], st[r-(1 << k)+1][k]); } void init() { mp.clear(); scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); st[i][0] = a[i]; } for (int j = 1; j < 20; ++j) { if ((1 << j) > n) break; for (int i = 1; i <= n; ++i) { if (i + (1 << j) - 1 > n) break; st[i][j] = __gcd(st[i][j-1], st[i+(1<<(j-1))][j-1]); } } for (int i = 1; i <= n; ++i) { int goal, j = i, t; while (j <= n) { goal = query(i, j); int l = j, r = n, m; while (l <= r) { m = (l + r) >> 1; if (query(i, m) == goal) { t = m; l = m + 1; } else { r = m - 1; } } mp[goal] += (t - j + 1); j = t + 1; } } } void solve() { int q; scanf("%d", &q); while (q--) { int x, y; scanf("%d%d", &x, &y); int g = query(x, y); cout << g << ' ' << mp[g] << '\n'; } } int main() { freopen("test.txt", "r", stdin); int cas; scanf("%d", &cas); for (int tt = 1; tt <= cas; ++tt) { printf("Case #%d:\n", tt); init(); solve(); } }