您的位置:首页 > 其它

codeforces 475D CGCDSSQ (st表+数论)

2016-11-08 11:15 357 查看
D. CGCDSSQ

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

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


 is
a greatest common divisor of v1, v2, ..., vn,
that is equal to a largest positive integer that divides all vi.

Input

The first line of the input contains integer n, (1 ≤ n ≤ 105),
denoting the length of the sequence. The next line contains n space separated integers a1, ..., an,
(1 ≤ ai ≤ 109).

The third line of the input contains integer q, (1 ≤ q ≤ 3 × 105),
denoting the number of queries. Then follows q lines, each contain an integer xi,
(1 ≤ xi ≤ 109).

Output

For each query print the result in a separate line.

Examples

input
3
2 6 3
5
1
2
3
4
6


output
1
2
2
0
1


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


output
14
0
2
2
2
0
2
2
1
1


题解:st表+数论

可以用st表预处理出区间gcd,然后O(1)查询。

我们考虑枚举左端点,随着右端点的后移,区间gcd最多变化log(n)次,因为每次变化gcd都至少要减小一半,所以显然。

那么我们可以枚举左端点,然后二分gcd每次变化的位置,用map记录答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 300003
#define LL long long
using namespace std;
int n,m,f
[20],l
;
map<int,LL> ans;
int a
;
int gcd(int x,int y)
{
int r;
while (y){
r=x%y;
x=y;
y=r;
}
return x;
}
void solve()
{
for (int i=1;i<=n;i++) f[i][0]=a[i];
for (int j=1;j<=17;j++)
for (int i=1;i<=n;i++)
if (i+(1<<j)-1<=n) f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
int j=0;
for (int i=1;i<=n;i++){
if ((1<<(j+1))<=i) j++;
l[i]=j;
}
}
int calc(int x,int y)
{
int k=l[y-x];
return gcd(f[x][k],f[y-(1<<k)+1][k]);
}
int work(int pos,int l,int r,int x)
{
int ans=r+1;
while (l<=r) {
int mid=(l+r)/2;
if (calc(pos,mid)!=x) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
if (ans==r) return ans;
return ans-1;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
solve();
for (int i=1;i<=n;i++) {
int now=a[i]; int x=i;
while (true) {
int last=x;
x=work(i,last,n,now);
now=calc(i,x);
ans[now]+=x-last+1;
if (x>=n) break;
x++; now=calc(i,x);
}
}
scanf("%d",&m);
for (int i=1;i<=m;i++) {
int x; scanf("%d",&x);
cout<<ans[x]<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: