zoukankan      html  css  js  c++  java
  • HDU 5869 Different GCD Subarray Query rmq+离线+数状数组

    题目链接:

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

    Different GCD Subarray Query

    Time Limit: 6000/3000 MS (Java/Others)
    Memory Limit: 65536/65536 K (Java/Others)
    #### 问题描述 > This is a simple problem. The teacher gives Bob a list of problems about GCD (Greatest Common Divisor). After studying some of them, Bob thinks that GCD is so interesting. One day, he comes up with a new problem about GCD. Easy as it looks, Bob cannot figure it out himself. Now he turns to you for help, and here is the problem: > > Given an array a of N positive integers a1,a2,⋯aN−1,aN; a subarray of a is defined as a continuous interval between a1 and aN. In other words, ai,ai+1,⋯,aj−1,aj is a subarray of a, for 1≤i≤j≤N. For a query in the form (L,R), tell the number of different GCDs contributed by all subarrays of the interval [L,R].

    输入

    There are several tests, process till the end of input.

    For each test, the first line consists of two integers N and Q, denoting the length of the array and the number of queries, respectively. N positive integers are listed in the second line, followed by Q lines each containing two integers L,R for a query.

    You can assume that

    1≤N,Q≤100000

    1≤ai≤1000000

    输出

    For each query, output the answer in one line.

    样例输入

    5 3
    1 3 4 6 9
    3 5
    2 5
    1 5

    样例输出

    6
    6
    6

    题意

    给你n个数排成一行,每次询问求一段区间内的所有子串的不同的gcd的种数有多少。

    题解

    首先,要处理出所有的子区间是比较困难的,而且事实上很多子区间的gcd都是重复出现的,我们把区间右端点固定,那么随着左区间从右往左移,区间gcd的值成倍递减,所以我们取到的不同的gcd的值只有logAi种,处理出来之后,我们就可以用离线的方式,用线段树来求区间不同的值有几个,每个事件(处理出来的sigma(logA[i])个区间gcd)以左端点为准插入树状数组中维护一下(离线查询的线段树/树状数组可以参考[这个])。

    代码

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    //#define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=1e5+10;
    const int maxa=1e6+10;
    
    int gcd(int a,int b) {
        return b==0?a:gcd(b,a%b);
    }
    
    struct Node {
        int l,r,v;
        Node(int l,int r,int v):l(l),r(r),v(v) {}
    };
    
    bool cmp1(const Node& t1,const Node& t2) {
        return t1.r<t2.r;
    }
    
    int n,m;
    int arr[maxn],ans[maxn];
    int dp[maxn][20];
    void rmq_init() {
        for(int i=1; i<=n; i++) dp[i][0]=arr[i];
        for(int j=1; (1<<j)<=n; j++) {
            for(int i=1; i+(1<<j)-1<=n; i++) {
                dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
            }
        }
    }
    
    int query(int l,int r) {
        int k=0;
        while(l+(1<<k)-1<=r) k++;
        k--;
        return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
    }
    
    int sumv[maxn],mp[maxa];
    
    void add(int x,int v) {
        while(x<maxn) {
            sumv[x]+=v;
            x+=(-x)&x;
        }
    }
    
    int sum(int x) {
        int ret=0;
        while(x>0) {
            ret+=sumv[x];
            x-=x&(-x);
        }
        return ret;
    }
    
    void init(){
        clr(mp,0);
        clr(sumv,0);
    }
    
    int main() {
        while(scf("%d%d",&n,&m)==2&&n) {
            init();
            for(int i=1; i<=n; i++) scanf("%d",&arr[i]);
            rmq_init();
    
            //v表示区间的gcd.
            //处理出代表性的事件
            vector<Node> events;
            for(int i=1; i<=n; i++) {
                int r=i;
                while(r>0) {
                    int l=0,v=query(r,i);
                    events.pb(Node(r,i,v));
                    while(l+1<r) {
                        int mid=l+(r-l)/2;
                        int tmp=query(mid,i);
                        if(tmp==v) r=mid;
                        else l=mid;
                    }
                    r--;
                }
            }
    
            //v表示查询的id
            vector<Node> que;
    
            for(int i=0; i<m; i++) {
                int l,r;
                scf("%d%d",&l,&r);
                que.pb(Node(l,r,i));
            }
    
            sort(all(que),cmp1);
            sort(all(events),cmp1);
    
            //离线处理
            int j=0;
            rep(i,0,que.sz()) {
                while(j<events.sz()&&events[j].r<=que[i].r){
                    Node& e=events[j];
                    if(mp[e.v]){
                        add(mp[e.v],-1);
                    }
                    add(e.l,1);
                    mp[e.v]=e.l;
                    j++;
                }
                ans[que[i].v]=sum(que[i].r)-sum(que[i].l-1);
            }
    
            rep(i,0,m) prf("%d
    ",ans[i]);
        }
    
        return 0;
    }
    
    //end-----------------------------------------------------------------------
  • 相关阅读:
    OL8.0静默安装Oracle 19C
    MYSQL GTID 复制
    MYSQL异步复制
    YUM方式安装MYSQL5.7
    【学习笔记】大数据技术原理与应用(MOOC视频、厦门大学林子雨)
    【网友的】《一个程序猿的生命周期》读后感
    连载《一个程序猿的生命周期》-22.缺了一条腿的公司
    续评《遇到一位ITer,一位出租车司机,必看》
    遇到一位ITer,一位出租车司机,必看。
    连载《一个程序猿的生命周期》-21.而立之年,第一次跳槽,寻求转型
  • 原文地址:https://www.cnblogs.com/fenice/p/5872180.html
Copyright © 2011-2022 走看看