zoukankan      html  css  js  c++  java
  • 区间gcd问题 HDU 5869 离线+树状数组

    题目大意:长度n的序列, m个询问区间[L, R], 问区间内的所有子段的不同GCD值有多少种. 子段就是表示是要连续的a[]

    思路:固定右端点,预处理出所有的gcd,每次都和i-1的gcd比较,然后不断放入gcd即可。

    然后就是树状数组的更新,枚举右端点即可。然后我们知道,大区间不如小区间来的实惠,所以我们每次有重复gcd出现的时候,都要把大区间更换成小区间即可

    下午脑子有点不清楚。。。2333看别人的博客蒙了好久

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    /*
    先总体说一下思路:求出区间的gcd,再对右进行排序,再枚举右端即可
    */
    const int maxn = 1e5 + 5;
    int tree[maxn], a[maxn], pre[maxn * 10], ans[maxn];
    int n, q;
    vector<pair<int, int> >qq[maxn], v[maxn];
    
    int lowbit(int x) {return x & -x;}
    int gcd(int a, int b){
        return b == 0 ? a : gcd(b, a % b);
    }
    
    void update(int x, int val){
        for (int i = x; i <= n; i += lowbit(i)){
            tree[i] += val;
        }
    }
    
    int sum(int x){
        int ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) ans += tree[i];
        return ans;
    }
    
    void solve(){
        memset(pre, 0, sizeof(pre));
        memset(tree, 0, sizeof(tree));
    
        for (int i = 1; i <= n; i++){
            int len = v[i].size();
            for (int j = 0; j < len; j++){
                pair<int, int> g = v[i][j];
                if (pre[g.first]) update(pre[g.first], -1);
                pre[g.first] = g.second;
                update(g.second, 1);
            }
            len = qq[i].size();
            for (int j = 0; j < len; j++){
                pair<int, int> p = qq[i][j];
                ans[p.second] = sum(i) - sum(p.first - 1);
            }
        }
        for (int i = 1; i <= q; i++){
            printf("%d
    ", ans[i]);
        }
    }
    
    int main(){
        while (scanf("%d%d", &n, &q) == 2){
            for (int i = 1; i <= n; i++){
                scanf("%d", a + i);
                v[i].clear();
                qq[i].clear();
            }
            for (int i = 1; i <= n; i++){
                int len = v[i - 1].size();
                int val = a[i], pos = i;
                for (int j = 0; j < len; j++){
                    pair<int, int> p = v[i - 1][j];
                    int g = gcd(p.first, val);
                    if (g != val) {
                        v[i].pb(mk(val, pos));///要优先知道那一个区间里面的gcd
                        val = g;
                        pos = p.second;
                    }
                }
                v[i].pb(mk(val, pos));
            }
    /*
            for (int i = 1; i <= n; i++){
                int len = v[i].size();
                for (int j = 0; j < len; j++){
                    printf("%d&%d   ", v[i][j].first, v[i][j].second);
                }
                printf("
    ");
            }
    */
            for (int i = 1; i <= q; i++){
                int l, r; scanf("%d%d", &l, &r);
                qq[r].pb(mk(l, i));
            }
            solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    对Promise的研究4
    对Promise的研究3
    对Promise的研究2
    对promise的研究1
    数据结构_栈
    数据结构_队列(普通队列和双端队列)
    数据结构_链表(单链表,单向循环链表,双链表)
    数据库进行参数化,查询一行或多行语句
    数据库基础应用
    选择排序
  • 原文地址:https://www.cnblogs.com/heimao5027/p/5865036.html
Copyright © 2011-2022 走看看