题意翻译
给出一个长度为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;
}