[HDU 5042 GCD pair] 离线+按GCD相同分段

来源:互联网 发布:苹果美版网络锁查询 编辑:程序博客网 时间:2024/06/06 17:38

题目

http://acm.hdu.edu.cn/showproblem.php?pid=5042

分析

离线+按GCD相同分段

与ZOJ 3800思路很像,想法都是按照gcd相等的一段分段,因为gcd的性质,不会超过logN段

然后处理出所有的gcd和出现的次数,排序,再把所有询问离线,select挂到对应的gcd上,rank挂到对应的左段点上

然后从后往前枚举,再用上面的方法统计一次即可

时间复杂度O(Nlog^2N)

代码

/************************************************** *        Problem:  HDU 5042 *         Author:  clavichord93 *          State:  Accepted **************************************************/#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <vector>#include <algorithm>#include <cassert>#include <functional>using namespace std;typedef long long ll;const int MAX_N = 100005;int n, cntQuery;int a[MAX_N];char op[10];vector< pair<ll, int> > selects[MAX_N];vector< pair<int, int> > queries[MAX_N];int cntGcd;int gcd[MAX_N * 20];int rank[MAX_N];ll cnt[MAX_N];ll tot[MAX_N];int stack[MAX_N];int entry[MAX_N];int _stack[MAX_N];int _entry[MAX_N];int curSelect[MAX_N];pair<ll, ll> ans[MAX_N];int main() {    #ifdef LOCAL_JUDGE    freopen("in.txt", "r", stdin);    #endif    int T;    scanf("%d", &T);    for (int cas = 1; cas <= T; cas++) {        memset(cnt, 0, sizeof(cnt));        memset(tot, 0, sizeof(tot));        for (int i = 0; i <= 100000; i++) {            selects[i].clear();            queries[i].clear();        }        scanf("%d %d", &n, &cntQuery);        for (int i = 1; i <= n; i++) {            scanf("%d", &a[i]);        }        cntGcd = 0;        {            int top = 0;            stack[0] = 0;            entry[0] = 0;            for (int i = 1; i <= n; i++) {                for (int j = 1; j <= top; j++) {                    stack[j] = __gcd(stack[j], a[i]);                }                int _top = 0;                for (int j = 1; j <= top; j++) {                    if (stack[j] != stack[j - 1]) {                        _top++;                        _stack[_top] = stack[j];                        _entry[_top] = entry[j];                    }                }                if (!_top || _stack[_top] != a[i]) {                    _top++;                    _stack[_top] = a[i];                    _entry[_top] = i;                }                top = _top;                entry[top + 1] = i + 1;                for (int j = 1; j <= top; j++) {                    stack[j] = _stack[j];                    entry[j] = _entry[j];                }                for (int j = 1; j <= top; j++) {                    tot[stack[j]] += entry[j + 1] - entry[j];                    gcd[++cntGcd] = stack[j];                }            }        }        sort(gcd + 1, gcd + cntGcd + 1);        cntGcd = unique(gcd + 1, gcd + cntGcd + 1) - gcd - 1;        for (int i = 1; i <= cntGcd; i++) {            rank[gcd[i]] = i;        }        //for (int i = 1; i <= cntGcd; i++) {            //printf("%d ", gcd[i]);        //}        //printf("\n");        for (int i = 1; i <= cntQuery; i++) {            scanf("%s", op);            if (op[0] == 'S') {                ll k1, k2;                scanf("%I64d %I64d", &k1, &k2);                if (k1 <= cntGcd && k2 <= tot[gcd[k1]]) {                    selects[gcd[k1]].push_back(make_pair(k2, i));                }            }            else {                int l, r;                scanf("%d %d", &l, &r);                queries[l].push_back(make_pair(r, i));            }            ans[i] = make_pair(-1, -1);        }        for (int i = 1; i <= n; i++) {            sort(queries[i].begin(),  queries[i].end());        }        for (int i = 1; i <= cntGcd; i++) {            int x = gcd[i];            sort(selects[x].begin(), selects[x].end(), greater< pair<ll, int> >());            curSelect[x] = 0;        }        //for (int i = 1; i <= cntGcd; i++) {            //int x = gcd[i];            //for (int j = 0; j < (int)selects[x].size(); j++) {                //printf("%I64d ", selects[x][j].first);            //}            //printf("\n");        //}        {            int top = 0;            stack[0] = 0;            entry[0] = n + 1;            for (int i = n; i >= 1; i--) {                for (int j = 1; j <= top; j++) {                    stack[j] = __gcd(stack[j], a[i]);                }                int _top = 0;                for (int j = 1; j <= top; j++) {                    if (stack[j] != stack[j - 1]) {                        _top++;                        _stack[_top] = stack[j];                        _entry[_top] = entry[j];                    }                }                if (!_top || _stack[_top] != a[i]) {                    _top++;                    _stack[_top] = a[i];                    _entry[_top] = i;                }                top = _top;                entry[top + 1] = i - 1;                for (int j = 1; j <= top; j++) {                    stack[j] = _stack[j];                    entry[j] = _entry[j];                }                int sizeRank = queries[i].size();                int cur = 0;                for (int j = top; j >= 1; j--) {                    int x = stack[j];                    cnt[x] += entry[j] - entry[j + 1];                    {                        while (cur < sizeRank && queries[i][cur].first <= entry[j]) {                            ll first = rank[x];                            ll second = tot[x] - cnt[x] + queries[i][cur].first - entry[j + 1];                            ans[queries[i][cur].second] = make_pair(first, second);                            cur++;                        }                    }                    {                        int &cur = curSelect[x];                        int size = selects[x].size();                        while (cur < size && tot[x] - cnt[x] < selects[x][cur].first) {                            ll first = i;                            ll second = entry[j + 1] + selects[x][cur].first - tot[x] + cnt[x];                            ans[selects[x][cur].second] = make_pair(first, second);                            cur++;                        }                    }                }            }        }        printf("Case #%d:\n", cas);        for (int i = 1; i <= cntQuery; i++) {            if (ans[i].first == -1) {                printf("-1\n");            }            else {                printf("%I64d %I64d\n", ans[i].first, ans[i].second);            }        }    }    return 0;}<strong></strong>


0 0
原创粉丝点击