Hdu-5869 Different GCD Subarray Query(区间不同值离线算法)

185 篇文章 0 订阅
116 篇文章 0 订阅
Problem Description
This is a simple problem. The teacher gives Bob a list of problems about GCD (Greatest Common Divisor). After studying some of them, Bob thinks that GCD is so interesting. One day, he comes up with a new problem about GCD. Easy as it looks, Bob cannot figure it out himself. Now he turns to you for help, and here is the problem:
  
  Given an array a of N positive integers a1,a2,aN1,aN ; a subarray of a is defined as a continuous interval between a1 and aN . In other words, ai,ai+1,,aj1,aj is a subarray of a , for 1ijN . For a query in the form (L,R) , tell the number of different GCDs contributed by all subarrays of the interval [L,R] .
  
 

Input
There are several tests, process till the end of input.
  
  For each test, the first line consists of two integers N and Q , denoting the length of the array and the number of queries, respectively. N positive integers are listed in the second line, followed by Q lines each containing two integers L,R for a query.

You can assume that
  
     1N,Q100000
    
   1ai1000000
 

Output
For each query, output the answer in one line.
 

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

Sample Output
  
  
6 6 6
 

Source
 



题意:给n个数,m个询问,每次问[l,r]区间内的所有子区间的GCD的不同值有多少个。


分析:区间不同值有一种离线的做法,考虑到以每个数为右端点的所有区间最多有log(n)个不同值,我们可以预处理出以每个数为右端点的不同gcd值,然后按照从左到右的顺序处理每个询问,当区间的右端固定时,我们用树状数组记下每种答案左端最晚出现的位置,这样对于每个询问直接用r结尾的总方案数减去(l-1)结尾的总方案数来得到答案。


#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#define INF 0x3f3f3f3f
#define N 100005
using namespace std; 
typedef pair<int,int> pii;
typedef long long ll;
int n,q,ans[N],f[N],a[N],last[N*10];
vector<int> G[N];
int _gcd(int a,int b)
{
   if(b == 0) return a;
   a %= b;
   return _gcd(b,a);
}
int lowbit(int x)
{
	return x & (-x);
}
void Insert(int k,int x)
{
	while(k <= n)
	{
		f[k] += x;
		k += lowbit(k);
	}
}
int Find(int k)
{
	int ans = 0;
	while(k)
	{
		ans += f[k];
		k -= lowbit(k);
	}
	return ans;
}
struct thing
{
	int l,r;	
}ask[N];
int main()
{
	while(~scanf("%d%d",&n,&q))
	{
		memset(last,0,sizeof(last));
		memset(f,0,sizeof(f));
		for(int i = 1;i <= n;i++) 
		{
			scanf("%d",&a[i]);
			G[i].clear();
		}
		for(int i = 1;i <= q;i++) 
		{
			scanf("%d%d",&ask[i].l,&ask[i].r);
			G[ask[i].r].push_back(i);
		}
		vector<pii> pre;
		for(int i = 1;i <= n;i++)
		{
			vector<pii> tmp;
			pre.push_back(make_pair(a[i],i));
			for(pii v : pre)
			{
				if(tmp.size() && _gcd(v.first,a[i]) == tmp[tmp.size()-1].first) tmp[tmp.size()-1] = make_pair(_gcd(v.first,a[i]),v.second);
				else tmp.push_back(make_pair(_gcd(v.first,a[i]),v.second));
			}
			for(pii v : tmp)
			{
				if(!last[v.first] || last[v.first] < v.second)
				{
					if(last[v.first]) Insert(last[v.first],-1);
					last[v.first] = v.second;
					Insert(last[v.first],1);
				}
			}
			pre = tmp;
			for(int v : G[i]) ans[v] = Find(ask[v].r) - Find(ask[v].l-1);
		}
		for(int i = 1;i <= q;i++) printf("%d\n",ans[i]);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值