hdu 5381 莫队算法/gcd

来源:互联网 发布:questmobile数据 编辑:程序博客网 时间:2024/05/09 18:43

The sum of gcd

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 645    Accepted Submission(s): 279


Problem Description
You have an array A,the length of A is n
Let f(l,r)=ri=lrj=igcd(ai,ai+1....aj)
 

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integers n
Second line has n integers Ai
Third line has one integers Q,the number of questions
Next there are Q lines,each line has two integers l,r
1T3
1n,Q104
1ai109
1l<rn
 

Output
For each question,you need to print f(l,r)
 

Sample Input
251 2 3 4 531 32 31 444 2 6 931 32 42 3
 

Sample Output
9616182310
 

Author
SXYZ
 

Source
2015 Multi-University Training Contest 8
 


 
区间查询问题,考虑离线的做法。这题关键点是,假如已知k个数a1,...,ak的gcd,那么在原来k个数基础上加多一个数,也就是a1,...ak+1,k+1个数的gcd,要么不变,要么就是至少少了一个因数,而最小的因数就是2,相当于至少变为原来的一半。也就是说1-n个数的gcd最多变了logn次。那么到以第i个数结尾的gcd前面最多可以分为logn段,每一段内gcd相同。有了这个能在logn时间内求出第i个数对前面任意以i结尾的区间的答案的贡献。也是就是知道了[l,r],能在logn内知道[l,r+1]和[l,r-1]。这个时候就可以用莫队算法了。

在网上找了很多莫队算法的资料,感觉就这个最好懂Mo's algorithm  

这场多校是中学生出的。。。应该是之前中学生被人抱怨出题太难,所以这题数据范围放小了,常数小的O(n^2)算法就能800ms水过。。(每次处理出第r个数的logn段gcd区间直接向前遍历一遍更新所有[i,r]的答案),莫队算法只用180ms


#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <cctype>#include <string>#include <vector>#include <map>#include <set>#include <vector>#include <queue>#include <stack>#include <algorithm>using namespace std;typedef pair<int, int> P;typedef long long LL;#define fir first#define sec secondconst int maxn=1e5+10;int n,m,a[maxn];int siz,num;struct Query{    int l, r, id;    int st;    bool operator < (const Query& a) const    {        return st!=a.st ? st<a.st : r<a.r;    }};Query q[maxn];vector<P> seg[maxn], segr[maxn];int gcd(int a, int b){    int tmp;    while(b){        tmp=a%b;        a=b;        b=tmp;    }    return a;}LL ans[maxn];int main(){    int t;    cin>>t;    while(t--){        cin>>n;        for(int i=0; i<=n; i++) seg[i].clear(), segr[i].clear();        for(int i=0; i<n; i++) scanf("%d", a+i);        siz=sqrt(n);        num=(n+siz-1)/siz;        cin>>m;        for(int i=0; i<m; i++){            scanf("%d%d", &q[i].l, &q[i].r);            q[i].l--; q[i].r--;            q[i].id=i;            q[i].st=q[i].l/siz;        }        sort(q, q+m);        for(int i=0; i<n; i++){            if(i)            for(int j=0; j<seg[i-1].size(); j++){                int v=gcd(seg[i-1][j].sec, a[i]);                int tot=seg[i].size();                if(tot && seg[i][tot-1].sec==v)                    seg[i][tot-1].fir=seg[i-1][j].fir;                else                    seg[i].push_back(P(seg[i-1][j].fir, v));            }            int tot=seg[i].size();            if(tot && seg[i][tot-1].sec==a[i])                seg[i][tot-1].fir=i;            else seg[i].push_back(P(i, a[i]));        }        for(int i=n-1; i>=0; i--){            for(int j=0; j<segr[i+1].size(); j++){                int v=gcd(segr[i+1][j].sec, a[i]);                int tot=segr[i].size();                if(tot && segr[i][tot-1].sec==v)                    segr[i][tot-1].fir=segr[i+1][j].fir;                else                    segr[i].push_back(P(segr[i+1][j].fir, v));            }            int tot=segr[i].size();            if(tot && segr[i][tot-1].sec==a[i])                segr[i][tot-1].fir=i;            else segr[i].push_back(P(i, a[i]));        }        int l=0,r=0;        LL val=a[0];        for(int i=0; i<m; i++){            while(r<q[i].r){                r++;                for(int j=seg[r].size()-1; j>=0; j--){                    if(j &&l<=seg[r][j-1].first){                        val+=(LL)seg[r][j].sec*(seg[r][j].fir-seg[r][j-1].fir);                    }                    else{                        val+=(LL)seg[r][j].sec*(seg[r][j].fir-l+1);                        break;                    }                }            }            while(r>q[i].r){                for(int j=seg[r].size()-1; j>=0; j--){                    if(j &&l<=seg[r][j-1].fir){                        val-=(LL)seg[r][j].sec*(seg[r][j].fir-seg[r][j-1].fir);                    }                    else{                        val-=(LL)seg[r][j].sec*(seg[r][j].fir-l+1);                        break;                    }                }                r--;            }            while(l<q[i].l){                for(int j=segr[l].size()-1; j>=0; j--){                    if(j &&r>=segr[l][j-1].fir){                        val-=(LL)segr[l][j].sec*(segr[l][j-1].fir-segr[l][j].fir);                    }                    else{                        val-=(LL)segr[l][j].sec*(r-segr[l][j].fir+1);                        break;                    }                }                l++;            }            while(l>q[i].l){                l--;                for(int j=segr[l].size()-1; j>=0; j--){                    if(j &&r>=segr[l][j-1].fir){                        val+=(LL)segr[l][j].sec*(segr[l][j-1].fir-segr[l][j].fir);                    }                    else{                        val+=(LL)segr[l][j].sec*(r-segr[l][j].fir+1);                        break;                    }                }            }            ans[q[i].id]=val;        }        for(int i=0; i<m; i++)            printf("%I64d\n", ans[i]);    }    return 0;}





0 0
原创粉丝点击