hdu 5381 莫队算法/gcd

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
 
   
2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
 

Sample Output
 
   
9 6 16 18 23 10
 

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef pair P;
typedef long long LL;
#define fir first
#define sec second
const 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 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>m;
        for(int i=0; i=0; i--){
            for(int j=0; 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=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





你可能感兴趣的:(莫队算法,数据结构,数论,莫队算法,离线算法,区间查询)