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();
    }
}
hdu 5726

 

posted @ 2016-08-18 10:09  F.D.His.D  阅读(...)  评论(...编辑  收藏