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)
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
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
Recommend
预处理是必须的。
莫队算法,先将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[n].push_back( Ansblock( n,n,a[n] ) );
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,可能会超时。