codeforces 475D CGCDSSQ (st表+数论)

来源:互联网 发布:网络对战游戏排行 编辑:程序博客网 时间:2024/05/01 14:07

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
32 6 3512346
output
12201
input
710 20 3 15 1000 60 16101234561020601000
output
14022202211

题解: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 longusing namespace std;int n,m,f[N][20],l[N];map<int,LL> ans;int a[N];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;}}




0 0