CF475D CGCDSSQ

题意翻译

给出一个长度为n(1<=n<=10^{5})n(1<=n<=105) 的序列和q(1<=q<=3*10^{5})q(1<=q<=3∗105) 个询问,每个询问输出一行,询问gcd(a_l,a_{l+1},...,a_r)=xgcd(al​,al+1​,...,ar​)=x 的(i,j)(i,j) 的对数.

感谢@凌幽 提供的翻译

题目描述

Given a sequence of integers a_{1},...,a_{n}a1​,...,an​ and qq queries x_{1},...,x_{q}x1​,...,xq​ on it. For each query x_{i}xi​ you have to count the number of pairs (l,r)(l,r) such that 1<=l<=r<=n1<=l<=r<=n and gcd(a_{l},a_{l+1},...,a_{r})=x_{i}gcd(al​,al+1​,...,ar​)=xi​ .

 is a greatest common divisor of v_{1},v_{2},...,v_{n}v1​,v2​,...,vn​ , that is equal to a largest positive integer that divides all v_{i}vi​ .

输入输出格式

输入格式:

Given a sequence of integers a_{1},...,a_{n}a1​,...,an​ and qq queries x_{1},...,x_{q}x1​,...,xq​ on it. For each query x_{i}xi​ you have to count the number of pairs (l,r)(l,r) such that 1<=l<=r<=n1<=l<=r<=n and gcd(a_{l},a_{l+1},...,a_{r})=x_{i}gcd(al​,al+1​,...,ar​)=xi​ .

 is a greatest common divisor of v_{1},v_{2},...,v_{n}v1​,v2​,...,vn​ , that is equal to a largest positive integer that divides all v_{i}vi​ .

输出格式:

For each query print the result in a separate line.

输入输出样例

输入样例#1: 复制

3
2 6 3
5
1
2
3
4
6

输出样例#1: 复制

1
2
2
0
1

输入样例#2: 复制

7
10 20 3 15 1000 60 16
10
1
2
3
4
5
6
10
20
60
1000

输出样例#2: 复制

14
0
2
2
2
0
2
2
1
1

对于此类题目,往往都跟某些特别的性质有关

问自己:为什么是gcd? 为什么编者要出gcd? 为什么不能是和或别的东西?

1、卡你时限,那提高O就好了

2、gcd有什么特别的性质——个数少(?),连续性(?)

用st表求出区间gcd,用map维护答案

对于每个区间左端点L,不同的R,不同的gcd总共只有一点点,不会超过50,

又因为gcd是单调递减的,所以可以用二分求出相同的gcd的范围

#include<cstdio>
#include<map>
#define ll long long
using namespace std;
inline int read()
{
	int ret=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
		ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret;
}

map<int,ll> ans;

int n;
const int N=3e5+5;
int a[N],lg[N],f[N][20],q[N];

inline int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}

inline int get(int l,int r)
{
	int k=lg[r-l+1];
	return gcd(f[l][k],f[r-(1<<k)+1][k]);
}

inline int find(int L,int R,int k)
{
	int ret=L,l=L,r=R;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(get(L,mid)==k) ret=mid,l=mid+1;
			else r=mid-1;
	}
	return ret;
}
int main()
{
	n=read();
	lg[0]=-1;
	for(int i=1;i<=n;i++)
		f[i][0]=a[i]=read(),
		lg[i]=lg[i>>1]+1;
	
	for(int j=1;j<=lg[n];j++)
		for(int i=1;i<=n-(1<<j)+1;i++)
			f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	
	int T=read();
	for(int i=1;i<=T;i++) 
		ans[q[i]=read()]=1;
	
	for(int i=1;i<=n;i++)
	{
		int t=a[i],now=i;
		while(now<=n)
		{
			int pre=now;
			now=find(now,n,t);
			if(ans[t]) ans[t]+=now-pre+1;
			now++;
			if(now<=n)t=get(i,now);
		}
	}

	for(int i=1;i<=T;i++)
		printf("%lld\n",ans[q[i]]-1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/YYHS_WSF/article/details/82589588