您的位置:首页 > 大数据 > 人工智能

hdu 5381 The sum of gcd 原来有个算法叫莫队 2015 Multi-University Training Contest 8

2015-08-17 19:33 585 查看


The sum of gcd

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 659 Accepted Submission(s): 279



Problem Description

You have an array A,the
length of A is n

Let f(l,r)=∑ri=l∑rj=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

1≤T≤3

1≤n,Q≤104

1≤ai≤109

1≤l<r≤n



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



Recommend

wange2014 | We have carefully selected several similar problems for you: 5395 5394 5393 5392 5391

预处理是必须的。

莫队算法,先将n个数以长度为sqrt(n)进行划分,

对于每一个数,他与其它数gcd后的结果最多有32种(2^32 = 4 294 967 296),

以不同的值所在区域为标准储存,预处理以x为ri,以x为le 的区间gcd和,node R[x][最多32个] {int le, ri;LL gcd;}(并用结构体记录位置,)

将查询排序,以le所属块编号在前面的排在前,若块相同,ri小的在前。

莫队算法的思想是,两个相邻的查询x1,x2之间,用x1的结果加减乘除得到x2的结果,而且是一个数一个数的移动。

什么意思?就是假如x1:( 3,5 ) ,x2(3 ,7),那么计算玩x1(3,5)后,再计算(3,6),再计算(3,7),两个计算。

如果是x1(3,5) ,x2(4,7),那么x1(3,5)->(4,5)->(4,6)->x2(4,7);

假如按照上面的排序了,那么在每一块中,最多移动n+sqrt(n)次(约等于n),每一移动一次最多32次计算找到对应位置的gcd,有sqrt(n)块查询。

所以总的复杂度大约是O(n*sqrt(n) *32); (o( n^1.5 *32 ) )

(PS;预处理R[x][]的时候可以利用前面一个数的结论,若是得到R,(以x为ri)从1开始到n (因为要向左找),若是得到L,从n到1)。

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   num<<1,le,mid
#define rson    num<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)

using namespace std;
const int INF =0x3f3f3f3f;
const int maxn= 10000+10   ;
//const int maxm=    ;
//const int INF=    ;
typedef long long ll;
const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
//by yskysker123
int a[maxn];
int n,m,block;

struct Que
{
    int le,ri,pos;
    ll ans;
}que[maxn];

struct Ansblock
{
   int le,ri;
   ll  gcd;
   Ansblock(){}
   Ansblock(int l,int r,ll gc):le(l),ri(r),gcd(gc){  }

}  ;
vector<Ansblock>L[maxn],R[maxn];

inline bool cmp(Que x,Que y)
{
    if( x.pos/block==y.pos/block)
        return x.ri<y.ri;
    return x.le<y.le;
}
inline bool cmp2(Que x,Que y)
{
    return x.pos<y.pos;
}
void Pre()
{
    L
.push_back( Ansblock( n,n,a
 ) );
    for(int i=n-1;i>=1;i--)
    {
        int le=i,ri=i;
        ll gcd=a[i];
        int tmp;
        for(int j=0;j<L[i+1].size();j++)
        {
            int tmp= __gcd( gcd,L[i+1][j].gcd     );
            if( gcd!= tmp )
            {
                L[i].push_back( Ansblock(   le,ri,gcd  )        );
                gcd=tmp;
                le=ri+1;
            }

           ri=L[i+1][j].ri;
        }
        L[i].push_back(Ansblock( le,ri,gcd )  );
    }
    R[1].push_back(Ansblock( 1,1,a[1] )      );
    for(int i=2;i<=n;i++)
    {
        int le=i,ri=i;
        ll gcd=a[i];
        int tmp;
        for(int j=0;j<R[i-1].size();j++)
        {
            int tmp=__gcd(gcd,R[i-1][j].gcd);
            if(gcd!=tmp)
            {
                R[i].push_back(Ansblock( le,ri,gcd  )   );
                gcd=tmp;
                ri=le-1;
            }
           le=R[i-1][j].le;
        }
        R[i].push_back(  Ansblock(le,ri,gcd         ) );
    }
}
ll queryR(int le,int ri)
{

    ll ans=0;
    int x=le;
    for(int i=0;i<R[ri].size();i++)
    {
        if(  R[ri][i].le <= x && x<= R[ri][i].ri  )
        {

                ans+=R[ri][i].gcd  *(    R[ri][i].ri-x+1     );
                return ans;
        }

        ans +=(R[ri][i].ri-R[ri][i].le+1)*R[ri][i].gcd;
    }

}

ll queryL(int le,int ri)
{
    ll ans=0;
    int x=ri;
    for(int i=0;i<L[le].size() ;i++)
    {
        if(L[le][i].le<=x&&x<=L[le][i].ri)
        {

       ans+=L[le][i].gcd*( x-L[le][i].le+1  );
        return  ans;
        }

        ans+=(L[le][i].ri-L[le][i].le+1)*L[le][i].gcd;
    }

}

void Cal()
{
    sort(que+1,que+1+m,cmp);
    ll ans=0;
    int le=1,ri=0;
    for(int i=1;i<=m;i++)
    {
        for(    ;ri<que[i].ri    ;ri++      )   ans+=queryR(  le,ri+1);
        for(    ;ri>que[i].ri    ;ri--      )   ans-=queryR(le,ri);

        for(    ;le>que[i].le;le--  )   ans+=queryL( le-1,ri );
        for(    ;le<que[i].le;le++  )   ans-=queryL(le,  ri);
        que[i].ans=ans;
    }
    sort(que+1,que+1+m,cmp2);
    for(int i=1;i<=m;i++)
    {
        printf("%lld\n",que[i].ans);
    }

}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        FOR1(i,n)
        {
            L[i].clear();
            R[i].clear();
            scanf("%d",&a[i]);
        }
        scanf("%d",&m);
        FOR1(i,m)
        {
            scanf("%d%d",&que[i].le,&que[i].ri);
            que[i].pos=i;
        }
        block=sqrt(n);
        Pre();
        Cal();

    }

    return 0;
}
/*
2
5
1 2 3 4 5
3
1 3
2 3
1 4
*/


ps: 此代码 hdu 上 G++ 大约800ms到1000+ ms,可能会超时。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: