You are given a sequence {A0, A1, ..., AN-1} and an integer set called GS. Defined a function called G(L, R) on A, where G(L, R) = GCD(Ai) (L ≤ i< R) that is the greatest common divisor of all the integers in the subsequence {AL, AL+1, ..., AR-1}.
Now There're several questions for you. Give you three integers L, R and g, where g is an integer in GS. You need to calculate how many integer pairs (l, r) satisfy the condition that G(l, r) = g and L ≤ l < r ≤ R.
Input
Input will consist of multiple test cases. The first line of each case contains three integers N, M, Q (1≤ N, Q≤ 100000, 1 ≤ M ≤ 50), separated by spaces. The second line contains N integers, A0, A1, ..., AN-1 (1≤ Ai≤ 100000). The third line contains M integers, indicating the set GS. Every integer in GS is positive and less than 2000. For the next Q line, each line contains three integers, L, R, g (0≤ L< R≤ N, g∈ GS).
Output
For each case, output Q lines. Each line contains an integer, indicating the answer for the query.
Sample Input
4 4 4 1 2 3 4 1 2 3 4 0 4 1 0 4 2 0 4 3 0 4 4
Sample Output
7 1 1 1
Author: LIN, Xi
Source: ZOJ Monthly, August 2014
题目大意:给你N个数,和一个大小为M的集合,有Q组询问,每一组都询问[L,R-1]的区间的子区间GCD值为g的有多少个,g是集合中的一个数。
解题思路:
首先,注意到M只有50,可以预处理。
然后,GCD对于区间有非增的性质,那么对于数组A中的一个数Ai,以i为左端点的子区间GCD=g的是有范围的,我们可以维护这个区间,不妨设为[L,R],
L作为第一个使得区间[i,L]的GCD为g的下标,即min{x|GCD(i,x)==g}
R作为最右边是g的倍数的下标的后一位,即max{x|A[x]%g==0}
那么范围只有以下几种情况:
1. Ai%g!=0 范围不存在
2. Ai%g==0 L不存在,R存在
3. Ai%g==0 L,R都存在
通过区间GCD删除一个数后不会小于原来的值,我们可以发现L,R具有单调性
那么可以用扫描线处理出以每个点为左端点,GCD为M中的一个数的符合的范围
有了这个下面就简单多了。
离线排序,通过M把询问分类,对于每一类按询问区间的右端点排序,把大于右端点的点的范围全部插入线段数,然后询问区间左端点即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 100010
#define max(a,b) (a>=b ? a:b)
#define ll long long
using namespace std;
int n,m,q;
int v[maxn],s[maxn],f[maxn],LL[55][maxn],RR[55][maxn];
ll cc[55][maxn],ans[maxn];
struct Query{
int l,r,g,x;
friend bool operator<(Query a,Query b){
if(a.g!=b.g) return a.g<b.g;
return a.l>b.l;
}
}Q[maxn];
int Log[maxn];
void init(){
for(int i=1;i<maxn;i++) Log[i]=log(i*1.0)/log(2.0);
}
void read(){
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
for(int i=1;i<=m;i++) scanf("%d",&s[i]);
sort(s+1,s+m+1);
for(int i=1;i<=m;i++) f[s[i]]=i;
for(int i=1;i<=q;i++) scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].g),Q[i].x=i;
}
int dp[maxn][20];
void RMQ(){
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++) dp[i][0]=v[i];
for(int i=1;i<20;i++){
for(int j=1;j+(1<<i>>1)<=n;j++){
dp[j][i]=__gcd(dp[j][i-1],dp[j+(1<<i>>1)][i-1]);
}
}
}
int query_RMQ(int l,int r){
int h=Log[r-l+1];
return __gcd(dp[l][h],dp[r-(1<<h)+1][h]);
}
struct tree{
int l,r;
ll s,lz;
}a[maxn<<2];
void build(int l,int r,int k){
a[k].l=l,a[k].r=r,a[k].s=0,a[k].lz=0;
if(l<r){
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
}
void pushdown(int k){
if(a[k].lz){
a[k<<1].s+=(a[k<<1].r-a[k<<1].l+1)*a[k].lz;
a[k<<1|1].s+=(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lz;
a[k<<1].lz+=a[k].lz;
a[k<<1|1].lz+=a[k].lz;
a[k].lz=0;
}
}
void insert(int l,int r,int k){
if(l<=a[k].l&&a[k].r<=r){
a[k].s+=(r-l+1);
a[k].lz++;
}else{
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(r<=mid) insert(l,r,k<<1);
else if(l>mid) insert(l,r,k<<1|1);
else insert(l,mid,k<<1),insert(mid+1,r,k<<1|1);
a[k].s=a[k<<1].s+a[k<<1|1].s;
}
}
ll query(int l,int r,int k){
if(l<=a[k].l&&a[k].r<=r){
return a[k].s;
}else{
pushdown(k);
int mid=(a[k].l+a[k].r)>>1;
if(r<=mid) return query(l,r,k<<1);
else if(l>mid) return query(l,r,k<<1|1);
else return query(l,mid,k<<1)+query(mid+1,r,k<<1|1);
}
}
void solve(){
RMQ();
memset(cc,0,sizeof cc);
for(int i=1;i<=m;i++){
int L=1,R=1;
for(int j=1;j<=n;j++){
L=max(L,j),R=max(R,j);
int GCD;
if(v[j]%s[i]==0){
GCD=query_RMQ(j,L);
if(GCD!=s[i]){
while(L<=n&&__gcd(GCD,v[L])!=s[i]&&GCD!=1) GCD=__gcd(GCD,v[L++]);
}
while(R<=n&&v[R]%s[i]==0) R++;
}
LL[i][j]=L,RR[i][j]=R;
if(GCD!=s[i]) L=1;
}
}
/*for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
cout<<i<<" "<<j<<" "<<LL[i][j]<<" "<<RR[i][j]<<endl;
}
}*/
sort(Q+1,Q+q+1);
for(int i=1,j;i<=q;i++){
if(Q[i].g!=Q[i-1].g) build(1,n,1),j=n;
int z=f[Q[i].g];
Q[i].l++;
while(j>=Q[i].l){
if(RR[z][j]>LL[z][j]) insert(LL[z][j],RR[z][j]-1,1);
j--;
}
ans[Q[i].x]=query(Q[i].l,Q[i].r,1);
}
for(int i=1;i<=q;i++){
printf("%lld\n",ans[i]);
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
while(~scanf("%d%d%d",&n,&m,&q)){
read();
solve();
}
return 0;
}