zoukankan      html  css  js  c++  java
  • 2016 大连网赛---Different GCD Subarray Query(GCD离散+树状数组)

    题目链接

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

    Problem Description
    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,aN1,aN; a subarray of a is defined as a continuous interval between a1 and aN. In other words, ai,ai+1,,aj1,aj is a subarray of a, for 1ijN. For a query in the form (L,R), tell the number of different GCDs contributed by all subarrays of the interval [L,R].
      
     
    Input
    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 
      
        1N,Q100000 
        
       1ai1000000
     
    Output
    For each query, output the answer in one line.
     
    Sample Input
    5 3
    1 3 4 6 9
    3 5
    2 5
    1 5
     
    Sample Output
    6
    6
    6
     
    Source
     
    Recommend
    wange2014   |   We have carefully selected several similar problems for you:  5877 5876 5874 5873 5872 
     
    题意:输入N和Q,表示有N个数的一个序列,Q次询问,每次输入 l 和 r 表示一个区间,求这个区间不同的最大公倍数的个数(由这个区间的子区间得到);
     
    思路:对数列进行GCD离散处理(~我也是才知道还有这样的离散~) 
           
    for(int i=1;i<=N;i++)
            {
                int tot=a[i],pos=i;
                for(int j=0;j<v[i-1].size();j++)
                {
                    int  r=__gcd(a[i],v[i-1][j].first);
                    if(tot!=r)
                    {
                       v[i].push_back(make_pair(tot,pos));
                       tot=r;  pos=v[i-1][j].second;
                    }
                }
                v[i].push_back(make_pair(tot,pos));
            }
           然后对Q次询问离线处理,先输入Q次询问的区间,然后按右端点从小到大排序,i从1~N循环,当i==node[len].r  则 ans[node[len].id]=Sum(i)-Sum(node[len].l-1) ;
    可以方便快速的用树状数组处理;
     
    代码如下:
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <map>
    #include <vector>
    using namespace std;
    int a[100005];
    int c[1000005];
    int vis[1000005];
    int sum[100005];
    struct Node
    {
        int l,r;
        int id;
    }node[100005];
    bool cmp(const Node s1,const Node s2)
    {
        return s1.r<s2.r;
    }
    vector<pair<int,int> > v[100005];
    
    int __gcd(int x,int y)
    {
        int r=x%y;
        x=y;
        y=r;
        if(r==0) return x;
        return __gcd(x,y);
    }
    int Lowbit(int t)
    {
        return t&(t^(t-1));
    }
    int Sum(int x)
    {
        int sum = 0;
        while(x > 0)
        {
            sum += c[x];
            x -= Lowbit(x);
        }
        return sum;
    }
    void add(int li,int t)
    {
        while(li<=1000005)
        {
            c[li]+=t;
            li=li+Lowbit(li);
        }
    }
    int main()
    {
        int N,Q;
        while(scanf("%d%d",&N,&Q)!=EOF)
        {
            for(int i=1;i<=N;i++) scanf("%d",&a[i]);
            for(int i=1;i<=N;i++)
            {
                int tot=a[i],pos=i;
                for(int j=0;j<v[i-1].size();j++)
                {
                    int  r=__gcd(a[i],v[i-1][j].first);
                    if(tot!=r)
                    {
                       v[i].push_back(make_pair(tot,pos));
                       tot=r;  pos=v[i-1][j].second;
                    }
                }
                v[i].push_back(make_pair(tot,pos));
            }
    
            for(int i=0;i<Q;i++)
                scanf("%d%d",&node[i].l,&node[i].r),node[i].id=i;
            sort(node,node+Q,cmp);
            memset(c,0,sizeof(c));
            memset(vis,0,sizeof(vis));
            int len=0;
            for(int i=1;i<=N;i++)
            {
                for(int j=0;j<v[i].size();j++)
                {
                    int s1=v[i][j].first;
                    int s2=v[i][j].second;
                    if(vis[s1]){
                        add(vis[s1],-1);
                    }
                    vis[s1]=s2;
                    add(s2,1);
                }
                while(node[len].r==i)
                {
                    sum[node[len].id]=Sum(i)-Sum(node[len].l-1);
                    len++;
                }
            }
            for(int i=0;i<Q;i++)
                printf("%d
    ",sum[i]);
            for(int i=0;i<=N;i++)
                v[i].clear();
        }
        return 0;
    }
  • 相关阅读:
    DBAccess
    业务耗时及数组
    QB资料学习.01
    格式化参数
    日志记录.02_线程处理
    nginx 开启gzip
    js 变量提升和函数提升
    js 深拷贝 vs 浅拷贝
    js 伪数组 转 数组
    js 对象原型和原型链
  • 原文地址:https://www.cnblogs.com/chen9510/p/5867587.html
Copyright © 2011-2022 走看看