码迷,mamicode.com
首页 > 编程语言 > 详细

HDOJ 5381 The sum of gcd 莫队算法

时间:2017-05-12 09:33:22      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:ini   names   problem   bsp   let   idt   break   while   bool   


大神题解:

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 ,the length of  is 
Let 
 

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 
Second line has  integers 
Third line has one integers ,the number of questions
Next there are Q lines,each line has two integers ,



 

Output
For each question,you need to print 
 

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\n",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;
}



HDOJ 5381 The sum of gcd 莫队算法

标签:ini   names   problem   bsp   let   idt   break   while   bool   

原文地址:http://www.cnblogs.com/gavanwanggw/p/6843891.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!