hdu 5869 Different GCD Subarray Query 2016ACM/ICPC大连赛区网络赛1002

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
 

调了蛮久的。。码力太差了

某个数结尾,不同的GCD段一共只有log段

这样我们可以离线处理询问。按照右端点排序。

扫描的时候记录这个点往左的各个不同gcd出现的最后位置。用树状数组维护区间和

然后直接统计答案即可

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int tr[1000001];
int fx[1000001];
int a[100001];
inline int gcd(int x,int y)
{
//	printf("%d %d\n",x,y);
	int m=x%y;
	while(m!=0)
	{
		x=y;
		y=m;
		m=x%y;
	}
	return y;
}
inline int lowbit(int x)
{
	return x&(-x);
}
inline void inc(int d,int x)
{
	if(d==0)
		return ;
	int i;
	for(i=d;i<=1000000;i+=lowbit(i))
		tr[i]+=x;
}
inline int sum(int d)
{
	int i,ans=0;
	for(i=d;i>=1;i-=lowbit(i))
		ans+=tr[i];
	return ans;
}
struct question
{
	int l,r,p;
	bool operator <(question y) const
	{
		return r<y.r;
	}
}ask[100001];
int ans[100001];
int qt[1000001],qq[1000001];
bool v[1000001];
set<int> qx;
int main()
{
	int n,q;
	while(scanf("%d%d",&n,&q)!=EOF)
	{
		memset(tr,0,sizeof(tr));
		memset(fx,0,sizeof(fx));
		int i,j;
		for(i=1;i<=n;i++)
			scanf("%d",&a[i]);
		for(i=1;i<=q;i++)
		{
			scanf("%d%d",&ask[i].l,&ask[i].r);
			ask[i].p=i;
		}
		sort(ask+1,ask+1+q);
		int d=1;
		int s=0;
		int la=0;
		memset(v,false,sizeof(v));
		for(i=1;i<=n;i++)
		{
	//		printf("%d\n",i);
			s=0;
			int r=0;
			for(j=1;j<=la;j++)
			{
				int xt=gcd(qq[j],a[i]);
				if(fx[xt]==0)
				{
					r++;
					qt[r]=xt;
					fx[xt]=fx[qq[j]];
					inc(fx[xt],1);
					v[xt]=true;
				}
				else if(!v[xt])
				{
					r++;
					qt[r]=xt;
					inc(fx[xt],-1);
					fx[xt]=fx[qq[j]];
					inc(fx[xt],1);
					v[xt]=true;
				}
				else if(v[xt]&&fx[qq[j]]>fx[xt])
				{
					inc(fx[xt],-1);
					fx[xt]=fx[qq[j]];
					inc(fx[xt],1);
				}
			}
			bool flag=false;
			if(fx[a[i]]==0)
			{
				r++;
				qt[r]=a[i];
				fx[a[i]]=i;
				inc(fx[a[i]],1);
			}
			else if(fx[a[i]]!=i)
			{
				r++;
				qt[r]=a[i];
				inc(fx[a[i]],-1);
				fx[a[i]]=i;
				inc(fx[a[i]],1);
			}
			while(ask[d].r==i)
			{
				if(ask[d].l!=ask[d].r)
					ans[ask[d].p]=sum(i)-sum(ask[d].l-1);
				else
					ans[ask[d].p]=1;
				d++;
			}
			la=r;
			for(j=1;j<=r;j++)
			{
				qq[j]=qt[j];
				v[qt[j]]=false;
			}
		}
		for(i=1;i<=q;i++)
			printf("%d\n",ans[i]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值