• hdu 5869 区间gcd的求法及应用


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

    题解:

      1.因为n个数的gcd等于前n-1个数的gcd值再于第n个数gcd一下的值,再加上如果固定终点,区间向前延伸越多gcd必定是非严格递减的,所以我们可以预处理出以每一个数为终点的所有的后缀的gcd,每次求出第i个数为终点后记录下所有的gcd值再与第i+1个数求gcd,这个很好做。

      2.将所有的查询按右区间从小到大排序,同时将第一步记录的值在树状数组中更新,然后用树状数组区间求和就好了,这一步在代码里面解释

    #include <stdio.h>  
    #include <string.h>  
    #include <iostream>  
    #include <algorithm>  
    #include <stack>  
    #include <vector>  
    #include <queue>  
    #include <set>  
    #include <map>  
    #include <string>  
    #include <math.h>  
    #include <stdlib.h>  
    #include <time.h> 
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std;
    #define PF(x) cout << "debug: " << x << " ";
    #define EL cout << endl;
    #define PC(x) puts(x);
    typedef long long ll;
    #define CLR(x, v) sizeof (x, v, sizeof(x))
    using namespace std;
    const int INF = 0x5f5f5f5f;
    const int maxn = 2e5 + 10;
    const int mod = 1e9 + 7;
    const double eps = acos(-1);
    const double PI= atan(1.0)*4;
    int n,q,a[maxn],tree[maxn],vis[2000000],ans[maxn];
    vector<pair<int,int> >gd[maxn];
    struct st{
        int l,r,id;
    }qer[maxn];
    int gcd(int a,int b){
        return b == 0?a:gcd(b,a%b);
    }
    bool cmp(st x,st y){
        return x.r < y.r;
    }
    void Add(int k,int num){
        while(k <= n){
            tree[k] += num;
            k += k&(-k);
        }
    }
    int Sum(int k){
        int sum = 0;
        while(k > 0){
            sum += tree[k];
            k -= k&(-k);
        }
        return sum;
    }
    int main(){
        freopen("in.txt","r",stdin);
        while(~scanf("%d%d",&n,&q)){
            for(int i = 1;i <= n;i++){
                scanf("%d",&a[i]);
                gd[i].clear();
            }
            for(int i = 1;i <= n;i++){
                int x = a[i],y = i;
                for(int j = 0;j <gd[i-1].size();j++){
                    int t = gcd(gd[i-1][j].first,a[i]);
                    if(t != x){
                        gd[i].push_back(make_pair(x,y));
                        x = t,y = gd[i-1][j].second;//x记录从y位置到当前处理的i位置的gcd值,y为相同gcd中最右边的位置,最右边这个是必须的
                    }
                }
                gd[i].push_back(make_pair(x,y));
            }
           for(int i = 1;i <= q;i++){
                scanf("%d%d",&qer[i].l,&qer[i].r);
                qer[i].id = i;
           }
            sort(qer + 1,qer + 1 + q,cmp);
            memset(vis,0,sizeof(vis));
            memset(tree,0,sizeof(tree));
            int len = 1;
            for(int i = 1; i <= n;i++){
               // cout<<i<<":";
                for(int j = 0;j < gd[i].size();j++){
                   // cout<<gd[i][j].first<<"->"<<gd[i][j].second<<" ";
                    int c1 = gd[i][j].first,c2 = gd[i][j].second;
                  //如果这个gcd值c1出现过则更新其位置,根据非严格递减,                             这样一定能更新为最靠近当前的i的位置
                    if(vis[c1] > 0)                  
                        Add(vis[c1],-1);
                    vis[c1] = c2;
                    Add(c2,1);
                }
               // cout<<endl;
                while(qer[len].r == i){
                    ans[qer[len].id] = Sum(qer[len].r) - Sum(qer[len].l-1);
                    len++;
                }
            }
            for(int i = 1;i <= q;i++)
                printf("%d
    ",ans[i]);
        }
        return 0;
    }
                

    可以参考博客http://blog.csdn.net/angon823/article/details/52503408

  • 相关阅读:
    快速架设OpenStack云基础平台
    源码编译安装Nginx全程视频演示
    参加2012 Openstack亚太技术大会
    FFmpeg的安装与使用
    Linux下图解minicom安装
    [转]ARM/Thumb2PortingHowto
    [原]逆向iOS SDK -- _UIImageAtPath 的实现(SDK 6.1)
    [原]逆向iOS SDK -- +[UIImage imageNamed:] 的实现
    在 Emacs 中如何退出 Slime Mode
    [转] iOS ABI Function Call Guide
  • 原文地址:https://www.cnblogs.com/shimu/p/5869810.html
Copyright © 2020-2023  润新知