• Hdu5381-The sum of gcd(莫队)


    题意我就不说了
     
    解析: 莫队,先预处理出以i为右端点的区间的gcd值,有一些连续的区间的gcd值是相同的,比如[j,i],[j+1,i],[j+2,i]的gcd值是相同的,我们可以把[j,j+2]这个
    区间保存下来。同时也预处理出以i为左端点的,最后用莫队算法。详见代码实现。
     
    代码
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=10005;
    typedef __int64 LL;
    int N,M,A[maxn],block;
    struct Ques
    {
        int x,y,id;
        Ques(int x=0,int y=0,int id=0):x(x),y(y),id(id){}
        bool operator < (const Ques& t) const
        {
            int a=x/block,b=t.x/block;  //排序
            if(a!=b) return a<b;
            return y<t.y;
        }
    }ques[maxn];
    int gcd(int a,int b){ return b==0?a:gcd(b,a%b); }
    struct node
    {
        int id,g;
        node(int id=0,int g=0):id(id),g(g){}
    };
    vector<node> vl[maxn],vr[maxn];
    void GetLe()
    {
        for(int i=1;i<=N;i++)  //得到以i为右端点连续区间的gcd值
        {
            if(i==1){ vl[i].push_back(node(i,A[i])); continue; }
            int g=A[i],id=i;
            int Size=vl[i-1].size();
            for(int j=0;j<Size;j++)
            {
                node& t=vl[i-1][j];
                int ng=gcd(t.g,g);
                if(ng!=g) vl[i].push_back(node(id,g));
                g=ng; id=t.id;
            }
            vl[i].push_back(node(id,g));
        }
    }
    void GetRi()  //同理
    {
        for(int i=N;i>=1;i--)
        {
            if(i==N){ vr[i].push_back(node(i,A[i])); continue; }
            int g=A[i],id=i;
            int Size=vr[i+1].size();
            for(int j=0;j<Size;j++)
            {
                node& t=vr[i+1][j];
                int ng=gcd(t.g,g);
                if(ng!=g) vr[i].push_back(node(id,g));
                g=ng; id=t.id;
            }
            vr[i].push_back(node(id,g));
        }
    }
    LL WorkLe(int x,int y)
    {
        int Size=vl[y].size();
        int ny=y;
        LL ret=0;
        for(int i=0;i<Size;i++)
        {
            node& t=vl[y][i];
            if(t.id>=x)
            {
                ret+=(LL)t.g*(ny-t.id+1);
                ny=t.id-1; //跳过去
            }
            else{ ret+=(LL)t.g*(ny-x+1); break; }
        }
        return ret;
    }
    LL WorkRi(int x,int y)
    {
        int nx=x;
        LL ret=0;
        int Size=vr[x].size();
        for(int i=0;i<Size;i++)
        {
            node& t=vr[x][i];
            if(t.id<=y)
            {
                ret+=(LL)t.g*(t.id-nx+1);
                nx=t.id+1;
            }
            else { ret+=(LL)t.g*(y-nx+1); break; }
        }
        return ret;
    }
    LL ans[maxn];
    void solve()
    {
        for(int i=0;i<=N;i++) vl[i].clear(),vr[i].clear();
        block=(int)sqrt(N+0.5);  //分块
        sort(ques,ques+M);  //排序
        GetLe(); //得到左边连续相同的gcd区间
        GetRi(); //得到右边连续相同的gcd区间
        int x=1,y=0;
        LL ret=0;
        for(int i=0;i<M;i++)  //莫队的主要实现部分
        {
            Ques& q=ques[i];
            while(y<q.y){ y++; ret+=WorkLe(x,y); }
            while(y>q.y){ ret-=WorkLe(x,y); y--; }
            while(x<q.x){ ret-=WorkRi(x,y); x++; }
            while(x>q.x){ x--; ret+=WorkRi(x,y); }
            ans[q.id]=ret; //保存答案
        }
        for(int i=0;i<M;i++) printf("%lld
    ",ans[i]); //输出
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&N);
            for(int i=1;i<=N;i++) scanf("%d",&A[i]);//输入
            scanf("%d",&M);
            int x,y;
            for(int i=0;i<M;i++)
            {
                scanf("%d%d",&x,&y);
                ques[i]=Ques(x,y,i);  //离线保存查询
            }
            solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    搭建Android开发环境(linux x86_64)
    prisoner of love
    今天火箭和太阳打架了?
    归途,奋斗的起点
    年轻的希望
    老师:节日快乐!
    今天是我的生日吗?
    我亲爱的弟弟
    我的08,期盼09
    只是向往
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/5706230.html
Copyright © 2020-2023  润新知