zoukankan      html  css  js  c++  java
  • HDOJ 5381 The sum of gcd 莫队算法


    大神题解:

    http://blog.csdn.net/u014800748/article/details/47680899


    The sum of gcd

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 526    Accepted Submission(s): 226


    Problem Description
    You have an array A,the length of A is n
    Let f(l,r)=ri=lrj=igcd(ai,ai+1....aj)
     

    Input
    There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
    First line has one integers n
    Second line has n integers Ai
    Third line has one integers Q,the number of questions
    Next there are Q lines,each line has two integers l,r
    1T3
    1n,Q104
    1ai109
    1l<rn
     

    Output
    For each question,you need to print f(l,r)
     

    Sample Input
    2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
     

    Sample Output
    9 6 16 18 23 10
     

    Author
    SXYZ
     

    Source
     



    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const int maxn=10100;
    typedef long long int LL;
    
    struct G
    {
        G(){}
        G(int _id,LL _g):id(_id),g(_g){}
    
        int id;
    	LL g;
    
    	void toString()
    	{
    		printf("id: %d g: %lld
    ",id,g);
    	}
    };
    
    int n,a[maxn],Q;
    vector<G> VL[maxn],VR[maxn];
    struct Que
    {
        int L,R,id;
        bool operator<(const Que& que) const
        {
            if(L!=que.L) return L<que.L;
            return R<que.R;
        }
    }que[maxn];
    
    void PreInit()
    {
        /// get Left Point
        /// 以i为右端点,预处理出左边的段
        for(int i=1;i<=n;i++)
        {
            VL[i].clear();
            if(i==1)
            {
                VL[i].push_back(G(i,a[i]));
            }
            else
            {
    			LL curg=a[i];int L=i;
    			for(auto &it : VL[i-1])
    			{
    				int g=__gcd(it.g,curg);
    				if(g!=curg) VL[i].push_back(G(L,curg));
    				curg=g; L=it.id;
    			}
    			VL[i].push_back(G(L,curg));
            }
        }
        /// get Right Point
        /// 以i为左端点,预处理出右边的段
    	for(int i=n;i>=1;i--)
    	{
    		VR[i].clear();
    		if(i==n)
    		{
    			VR[i].push_back(G(i,a[i]));
    		}
    		else
    		{
    			LL curg=a[i];int R=i;
    			for(auto &it : VR[i+1])
    			{
    				int g=__gcd(curg,it.g);
    				if(g!=curg) VR[i].push_back(G(R,curg));
    				curg=g; R=it.id;
    			}
    			VR[i].push_back(G(R,curg));
    		}
    	}
    }
    
    /// 计算L,R之间的值
    LL calu(int type,int L,int R)
    {
    	LL ret=0;
    	if(type==0)
    	{
    		int tr=R;
    		for(auto &it : VL[R])
    		{
    			if(it.id>=L)
    			{
    				ret+=(tr-it.id+1)*it.g;
    				tr=it.id-1;
    			}
    			else
    			{
    				ret+=(tr-L+1)*it.g;
    				break;
    			}
    		}
    	}
    	else if(type==1)
    	{
    		int tr=L;
    		for(auto &it : VR[L])
    		{
    			if(it.id<=R)
    			{
    				ret+=(it.id-tr+1)*it.g;
    				tr=it.id+1;
    			}
    			else
    			{
    				ret+=(R-tr+1)*it.g;
    				break;
    			}
    		}
    	}
    	return ret;
    }
    
    LL ans[maxn];
    
    int main()
    {
    	int T_T;
    	scanf("%d",&T_T);
        while(T_T--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%d",a+i);
            PreInit();
    
    		scanf("%d",&Q);
            for(int i=0,l,r;i<Q;i++)
            {
                scanf("%d%d",&l,&r);
                que[i].L=l; que[i].R=r; que[i].id=i;
            }
            sort(que,que+Q);
    
    		int L=1,R=0; LL ret=0;
    		for(int i=0;i<Q;i++)
    		{
    			while(R<que[i].R)
    			{
    				R++;
    				ret+=calu(0,L,R);
    			}
    			while(R>que[i].R)
    			{
    				ret-=calu(0,L,R);
    				R--;
    			}
    			while(L<que[i].L)
    			{
    				ret-=calu(1,L,R);
    				L++;
    			}
    			while(L>que[i].L)
    			{
    				L--;
    				ret+=calu(1,L,R);
    			}
    			ans[que[i].id]=ret;
    		}
    
    		for(int i=0;i<Q;i++)
    			cout<<ans[i]<<endl;
        }
        return 0;
    }
    



  • 相关阅读:
    PHP观察者模式
    php减少损耗的方法之一 缓存对象
    php迭代器模式
    数据库安全措施的改进依据------未实践
    mysql利用phpmyadmin导入数据出现#1044错误 的可能原因
    两列布局的基本思路
    less1.5中的减错误
    ie63像素bug原因及解决办法不使用hack
    镜像翻转二叉树
    判断一个整数是否是 2 的幂次方
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6843891.html
Copyright © 2011-2022 走看看