codeforces 475D CGCDSSQ ST表+二分

点击打开链接链接

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.

Sample test(s)
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
给出一串数字  q个查询

问有几对l r使得从l到r的gcd为x

用线段树会T

ST表 然后二分 

代码如下

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define MAXN 111111
using namespace std;
int n,stgcd[MAXN][35],num[MAXN];
int prelog2[MAXN];
map<int ,long long > ans;
int gcd(int a,int b){
    if(b==0)
	return a;
    return gcd(b,a%b);
}
void init(){
    prelog2[1]=0;
    for(int i=2;i<=n;i++){
	prelog2[i]=prelog2[i-1];
	if((1<<prelog2[i]+1)==i)
	    prelog2[i]++;
    }
    for(int i=n;i>=1;i--){
	stgcd[i][0]=num[i];
	for(int j=1;(i+(1<<j)-1)<=n;j++){
	    stgcd[i][j]=gcd(stgcd[i][j-1],stgcd[i+(1<<j-1)][j-1]);
	}
    }
}
int getgcd(int l,int r){
    int len=r-l+1;
    return gcd(stgcd[l][prelog2[len]],stgcd[r-(1<<prelog2[len])+1][prelog2[len]]);
}
void solve(){
    for(int i=1;i<=n;i++){
	int ed=i,l,r,m,pos;
	while(ed<=n){
	    int xx=getgcd(i,ed);
	    l=ed,r=n,pos=-1;
	    while(l<=r){
		if(r-l<=1){
		    if(getgcd(i,r)==xx)
			pos=r;
		    else if(getgcd(i,l)==xx)
			pos=l;
		    break;
		}
		m=l+r>>1;
		if(getgcd(i,m)==xx)
		    l=m;
		else r=m;
	    }
	    ans[xx]+=pos-ed+1;
	    ed=pos+1;
	}
    }
}
int main(){
    int q,xx;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
	scanf("%d",&num[i]);
    init();
    solve();
    scanf("%d",&q);
    while(q--){
	scanf("%d",&xx);
	printf("%I64d\n",ans[xx]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值