题目链接:HDU 5381
题意:给出N个数,M个询问,对于每个询问,有一组[L,R],输出这个区间内所有子区间的GCD和。
思路:看完题目不难想到莫队,本来转移的时候想着可以rmq套个二分,然而超时了…
看了下别人题解才发现可以先预处理.
至于为什么可以这样预处理.我们发现 g c d gcd gcd 发生变化的话其值至少除2,因此种类顶多就 l o g n log n logn 种,预处理时间复杂度也就 O( n ∗ l o g n n*logn n∗logn) ,还是可以接受的.
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define Fi first
#define Se second
#define ll long long
#define inf 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define in(b) scanf("%d",&b)
#define mmin(a,b,c) min(a,min(b,c))
#define mmax(a,b,c) max(a,max(b,c))
#define debug(a) cout<<#a<<"="<<a<<endl;
#define debug2(a,b) cout<<#a<<"="<<a<<" "<<#b<<"="<<b<<endl;
#define debug3(a,b,c) cout<<#a<<"="<<a<<" "<<#b<<"="<<b<<" "<<#c<<"="<<c<<endl;
#define show_time cout << "The run time is:" << (double)clock() /CLOCKS_PER_SEC<< "s" << endl;
using namespace std;
const int N=3e5+10;
vector<pair<int,int> >vl[N],vr[N];
int a[N];
void init(int n)
{
for(int i=0;i<=n+1;i++) vl[i].clear(),vr[i].clear();
for(int i=1;i<=n;i++)
{
int gcd=a[i],p=i;
for(auto e:vr[i-1])
{
int tmp=__gcd(gcd,e.Se);
if(tmp!=gcd)
{
vr[i].push_back({p,gcd});
}
p=e.Fi;gcd=tmp;
}
vr[i].push_back({p,gcd});
}
for(int i=n;i>=1;i--)
{
int gcd=a[i],p=i;
for(auto e:vl[i+1])
{
int tmp=__gcd(gcd,e.Se);
if(tmp!=gcd)
{
vl[i].push_back({p,gcd});
}
p=e.Fi;gcd=tmp;
}
vl[i].push_back({p,gcd});
}
}
int len;
struct Node
{
int l,r,id,block;
Node(){}
Node(int L,int R,int Id)
{
l=L;r=R;id=Id;
block=l/len;
}
}Q[N];
bool cmp(Node a,Node b)//奇偶优化
{
if(a.block==b.block)
{
if(a.block&1)
return a.r<b.r;
else return a.r>b.r;
}
return a.l<b.l;
}
void add1(int l,int r,ll v,ll &ans)//左端点变化
{
int bef=l;
for(auto e :vl[l])
{
if(bef>r) break;
ans+=v*(min(r,e.Fi)-bef+1)*e.Se;
bef=e.Fi+1;
}
}
void add2(int l,int r,ll v,ll &ans)//右端点变化
{
int bef=r;
for(auto e :vr[r])
{
if(bef<l) break;
ans+=v*(bef-max(l,e.Fi)+1)*e.Se;
bef=e.Fi-1;
}
}
ll Ans[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n; scanf("%d",&n);
len=sqrt(n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int m; scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r;scanf("%d%d",&l,&r);
Q[i]=Node(l,r,i);
}
init(n);
sort(Q+1,Q+1+m,cmp);
int l,r;l=r=1;
ll ans=a[1];
for(register int i=1;i<=m;i++)
{
int ql=Q[i].l,qr=Q[i].r;
while(l<ql) add1(l++,r,-1ll,ans);
while(l>ql) add1(--l,r,1ll,ans);
while(r<qr) add2(l,++r,1ll,ans);
while(r>qr) add2(l,r--,-1ll,ans);
Ans[Q[i].id]=ans;
}
for(int i=1;i<=m;i++)
{
printf("%lld\n",Ans[i]);
}
}
return 0;
}
/*
*/