题目描述
小L最近迷上了刺绣,由于她对数字的执着,她在刺绣上刺了n个数字。
有一天,她突然觉得如果一段区间的gcd为她指定的一个数,她就会十分喜欢这一段区间。但是每天小L指定的数都会改变,这把小L给难倒了,聪明的你能帮帮她吗?
对于每个询问,即求有多少个区间的gcd为指定的数x。
在这道题中gcd(0,0)=0。
输入
第一行一个整数n,表示序列的长度。
第二行n个整数,序列中的第i个数ai。
第三行一个整数m,表示询问的个数。
接下来一行m个整数,第i个数表示第i个询问的数x。
输出
一行m个整数,表示对应的答案。
样例输入 Copy
3 2 6 3 5 1 2 3 4 6
样例输出 Copy
1 2 2 0 1
提示
对于30%的测试数据,n,m≤100。
对于50%的测试数据,n,m≤1000。
对于100%的测试数据,n,m≤100000,0≤ai,x≤10^9。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
int Max[MAXN][35],Min[MAXN][35];
int q,n,x;
map<int,int>mp;
int Query(int l,int r)
{
int k=log2(r-l+1);
return __gcd(Max[l][k],Max[r-(1<<k)+1][k]);//把拆出来的区间分别取最值
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>Max[i][0];
Min[i][0]=Max[i][0];
}
for(int j=1; j<=log2(n); j++)
{
for(int i=1; i+(1<<j)-1<=n; i++) //注意这里要控制边界
{
Max[i][j]=__gcd(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
}
}
for(int i=1; i<=n; i++)
{
int gcd=Max[i][0],t=i;
while(t<=n)
{
int l=t,r=n,ans;
while(l<=r)
{
int mid=(l+r)/2;
if(Query(i,mid)==gcd)
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
mp[gcd]+=(ans-t+1);
t=ans+1;
gcd=Query(i,t);
}
}
cin>>q;
for(int i=1; i<=q; i++)
{
cin>>x;
cout<<mp[x]<<endl;
}
return 0;
}