hdu 5381 莫队...

来源:互联网 发布:windows的运行在哪里 编辑:程序博客网 时间:2024/06/05 12:08


The sum of gcd

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


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


最难的不是莫队。。 而是。。 处理转移关系。。 神题

rmq可以用来预处理gcd也是第一次知道。。 

利用gcd特殊性质优化

#include <bits/stdc++.h> using namespace std;#define fi first#define se secondconst int maxn = 10010;typedef pair<int, int> pii;typedef long long ll;int gcd[maxn][20], mm[maxn];int n,q,a[maxn], unit;vector<pii> lef[maxn], rig[maxn];ll ans[maxn];struct node{    int l, r, id;    bool operator<(const node & b) const{        if( l/unit == b.l/unit) return r < b.r;        return l/unit < b.l/unit;    }}Query[maxn];void init(){    mm[0] = -1;    for(int i=1; i<=n; i++){        mm[i] = (i&(i-1)) == 0?mm[i-1]+1:mm[i-1];        gcd[i][0] = a[i];    }    for(int j=1; j<=mm[n]; j++)        for(int i=1; i+(1<<j)-1<=n; i++)            gcd[i][j] = __gcd(gcd[i][j-1], gcd[i+(1<<(j-1))][j-1]);}int query(int l, int r){    int k = mm[r-l+1];    return __gcd(gcd[l][k], gcd[r-(1<<k)+1][k]);}void go(){    for(int i=1; i<=n; i++)        lef[i].clear(), rig[i].clear();    int ans;    for(int i=1; i<=n; i++){        int L = 1, R = i, g = a[i], mid;        while(true){            while(L<=R){                mid = (L+R)>>1;                if(query(mid, i) == g) R = mid-1, ans = mid;                else L = mid + 1;            }            lef[i].push_back(make_pair(g, ans));            if(ans == 1) break;            R = ans - 1; L = 1; g = query(R, i);        }    }    for(int i=1; i<=n; i++){        int L = i, R = n, g = a[i], mid;        while(true){            while(L <= R){                mid = (L+R+1)>>1;                if(query(i, mid) == g) L = mid+1, ans = mid;                else R = mid-1;            }            rig[i].push_back(make_pair(g, ans));            if(ans == n) break;            L = ans + 1, R = n, g = query(i, L);        }    }}ll LEFT(int x, int L){    int p = x;    ll ans = 0;    int size = lef[x].size();    for(int i=0; i<size; i++){        int g = lef[x][i].first, pos = max(L, lef[x][i].second);        ans += (ll)g*(ll)(p - pos + 1);        p = pos - 1;        if( p < L ) break;    }    return ans;}ll RIGHT(int x, int R){    int p = x;    ll ans = 0;    int size = rig[x].size();    for(int i=0; i<size; i++){        int g = rig[x][i].fi, pos = min(R, rig[x][i].se);        ans += (ll)g*(ll)(pos - p + 1);        p = pos + 1;        if( p > R) break;    }    return ans;}void work(){    int L = 1;    int R = 0;    sort(Query+1, Query+q+1);    ll cnt = 0;    for(int i=1; i<=q; i++){        while(R<Query[i].r)            cnt += LEFT(++R, L);        while(R>Query[i].r)            cnt -= LEFT(R--, L);        while(L<Query[i].l)            cnt -= RIGHT(L++, R);        while(L>Query[i].l)            cnt += RIGHT(--L, R);        ans[Query[i].id] = cnt;    }}int main(){    int T;    cin>>T;    while(T--){        cin>>n;        unit = sqrt(n);        for(int i=1; i<=n; i++)            scanf("%d", a+i);        init();        go();        scanf("%d", &q);        for(int i=1; i<=q; i++){            scanf("%d %d", &Query[i].l, &Query[i].r);            Query[i].id = i;        }        work();        for(int i=1; i<=q; i++)            printf("%I64d\n", ans[i]);    }    return 0;}


0 0