ZOJ3800 GCD+离线线段树

来源:互联网 发布:淘宝海报在线制作 编辑:程序博客网 时间:2024/06/16 03:42
Calculation

Time Limit: 5 Seconds      Memory Limit: 262144 KB

You are given a sequence {A0A1, ..., AN-1} and an integer set called GS. Defined a function called G(LR) on A, where G(LR) = GCD(Ai) (L ≤ iR) that is the greatest common divisor of all the integers in the subsequence {ALAL+1, ..., AR-1}.

Now There're several questions for you. Give you three integers LR and g, where g is an integer in GS. You need to calculate how many integer pairs (lr) satisfy the condition that G(lr) = g and L ≤ l < r ≤ R.

Input

Input will consist of multiple test cases. The first line of each case contains three integers NMQ (1≤ NQ≤ 100000, 1 ≤ M ≤ 50), separated by spaces. The second line contains N integers, A0A1, ..., 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, LRg (0≤ LR≤ Ng∈ GS).

Output

For each case, output Q lines. Each line contains an integer, indicating the answer for the query.

Sample Input

4 4 41 2 3 41 2 3 40 4 10 4 20 4 30 4 4

Sample Output

7111

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 longusing 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;}


0 0
原创粉丝点击