HDU 5875 Function 2016亚洲区域赛大连网络赛

来源:互联网 发布:阿里在线编程难么 编辑:程序博客网 时间:2024/05/29 11:02

题意:给你n个数和询问,让你回答对一段区间去膜的结果。

题解:这个题的关键,在于我们要注意一个数取模的一个性质就是说 一个数对一个比这个数大的数取模这个数不变,如果对一个比这个数小的数取模,这个数最少变成原来的 1 / 2.有了这个性质我们不难发现一个数取模的收敛速度是非常快的。在 logn时间内就可以收敛到很小,这样我们就可以找一个区间内比这个数小的数去取模大的数我们就可以不管。不断寻找比取模完的数更小的,最接近这个数的数去取模。 怎么找呢 ? 我们可以二分第一个取模位置,通过 ST 表或者线段树树状数组之类的数据结构维护一个区间最小值即可

ps : 学到一个求log 下取整的递推方法 以 log2为例          lg2[i] = lg2[i / 2] + 1

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;const int maxn = 1e5 + 10;const int INF = 1e9 + 7;int lg2[maxn] = {0};int st[maxn][40] = {0};int a[maxn] = {0};int n;void init () {    for (int j = 1;(1 << j) <= n; ++ j){        for (int i = 1;i + (1 << j) - 1 <= n; ++ i) {            st[i][j] = min (st[i][j - 1],st[i + (1 << (j - 1))][j - 1]);        }    }}int rmq (int l,int r) {    int len = (r - l + 1);    len = lg2[len];    int ans = min (st[l][len],st[r - (1 << len) + 1][len]);    return ans;}int main () {    ios_base :: sync_with_stdio(false);    int t;    cin >> t;    for (int i = 2;i < maxn; ++ i) {        lg2[i] = lg2[i / 2] + 1;    }    while (t --) {        cin >> n;        memset (st,0,sizeof (st));        memset (a,0,sizeof (a));        for (int i = 1;i <= n; ++ i) {            cin >> a[i];            st[i][0] = a[i];        }        init();        int q;        cin >> q;        while (q --) {            int l,r;            cin >> l >> r;            if (l == r) {                cout << a[l] << endl;                continue ;            }            int ans = a[l];            int L = l + 1;            int R = r;            int flag = 1;            while (flag) {            while (L < R) {                int mid = (L + R) >> 1;                if (rmq (L,mid) <= ans) R = mid;                else {                    if (rmq (mid + 1,R) > ans) {                        flag = 0;                        break;                    }                    else {                        L = mid + 1;                    }                }            }                if (flag) ans %= a[L];                L ++,R = r;                if (L > r || ans == 0) break;            }            cout << ans << endl;        }    }        return 0;}


原创粉丝点击