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 ,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

2015 Multi-University Training Contest 8

#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;
}
时间: 2024-10-13 06:26:30

HDOJ 5381 The sum of gcd 莫队算法的相关文章

hdu5381 The sum of gcd]莫队算法

题意:http://acm.hdu.edu.cn/showproblem.php?pid=5381 思路:这个题属于没有修改的区间查询问题,可以用莫队算法来做.首先预处理出每个点以它为起点向左和向右连续一段的gcd发生变化的每个位置,不难发现对每个点A[i],这样的位置最多logA[i]个,这可以利用ST表用nlognlogA[i]的时间预处理,然后用二分+RMQ在nlogn的时间内得到.然后就是区间变化为1时的转移了,不难发现区间变化为1时,变化的答案仅仅是以变化的那一个点作为左端点或右端点的

hdu 5381 The sum of gcd 莫队+预处理

The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description You have an array A,the length of A is nLet f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj) Input There are multiple test cases. The first line

HDU 5381 The sum of gcd 莫队暴力

链接 题解链接:http://www.cygmasot.com/index.php/2015/08/15/hdu_5381/ 题意: 给定n长的序列 下面n个数给出这个序列 m个询问 下面m行给出询问的区间. 对于一个询问,输出这个区间内的任意子段的gcd 和. 思路: 因为一个数的gcd只会不变或下降,下降一次至少减半,下降至多32次,所以处理出每个数连续相同的gcd的区间. 然后暴力跑莫队. #pragma comment(linker, "/STACK:1024000000,1024000

(预处理+莫队算法)HDU - 5381 The sum of gcd

题意: 一个长度为n的数列,m次查询L到R之间所有连续子序列的gcd之和. 分析: 很明显的莫队算法. 很明显发现了gcd是单调递减的,并且最多存在32个的性质. 想了很久,脑补了许多种方法来拉伸L和R,但是都有漏洞. 实际上,这道题还是比较复杂的.. 在思考的过程中,我没有充分利用gcd的递减性质. 这题其实这题有共通之处,至少在我的做法上是这样的. 可以发现,在R向右拉伸的过程中,增加的和只是从L到R+1中的每一个后缀的和. 向左则为减,L的移动同理. 那么我们只要提前预处理每个位置的前缀所

hdu 5381 The sum of gcd(线段树+gcd)

题目链接:hdu 5381 The sum of gcd 将查询离线处理,按照r排序,然后从左向右处理每个A[i],碰到查询时处理.用线段树维护,每个节点表示从[l,i]中以l为起始的区间gcd总和.所以每次修改时需要处理[1,i-1]与i的gcd值,但是因为gcd值是递减的,成log级,对于每个gcd值记录其区间即可.然后用线段树段修改,但是是修改一个等差数列. #include <cstdio> #include <cstring> #include <vector>

HDU 5381 The sum of gcd (2015年多校比赛第8场)

1.题目描述:点击打开链接 2.解题思路:本题利用莫队算法解决.由于是第一次学习这个算法,因此研究了比较长的一段时间才弄懂.首先,莫队算法解决的问题是无修改的离线区间查询问题.该算法实际上是由曼哈顿距离最小生成树演变来的,由于要处理m个区间,可以将这m个区间看做二维平面上的点,那么处理这m个区间就等价于让这m点连通,且总的转移代价最小.这其实就是一个曼哈顿距离最小生成树问题. 经典的曼哈顿距离最小生成树的时间复杂度是O(NlogN),莫队算法的时间复杂度是O(N^1.5).不过本题还有一个地方,

[CSP-S模拟测试]:sum(数学+莫队)

题目传送门(内部题63) 输入格式 第一行有一个整数$id$,表示测试点编号.第一行有一个整数$q$,表示询问组数.然后有$q$行,每行有两个整数$n_i,m_i$. 输出格式 一共有$q$行,每行一个整数表示每组询问的答案$S_{n_i,m_i}$对$10^9+7$取模的结果. 样例 样例输入: 151 12 13 24 35 5 样例输出: 2371532 数据范围与提示 对于所有数据,$1\leqslant q,n_i,m_i\leqslant 10^5$. 题解 考场上把$80$分部分分

【BZOJ3781、2038】莫队算法2水题

[BZOJ3781]小B的询问 题意:有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数 题解:初学莫队算法,差不多明白了用莫队的情况,对于这种离线的,区间长度+1时可O(1)修改答案的题,运用莫队算法是最水的 将n分成sqrt(n)块,将询问按照左端点所在的块为第一关键字,右端点的具体位置为第二关键字排序,然后用指针l,r不断暴力平移到询问的左右端点处,

Hdu5145NPY and girls莫队算法

Problem Description NPY's girlfriend blew him out!His honey doesn't love him any more!However, he has so many girlfriend candidates.Because there are too many girls and for the convenience of management, NPY numbered the girls from 1 to n.These girls