rmq 预处理很裸
然后当l-r区间的最大公约数必然是第一个数a[l]的几个质因子相乘的形式,而它最多有log(1000000000)个质因子,所以枚举每个左端点二分次数时不会超过log(1000000000)次,但实际上脑补一下远没有这么多次不会超时,然后枚举每个左端点进行log(1000000000)次二分把结果存入map中
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define maxn 100005
#define maxv 1000000000ll
using namespace std;
int n,dp[maxn][20],a[maxn],m;
map<int,long long>mp;
int gcd(int a,int b)
{
while(b)
{
int t;
t = a%b;
a = b;
b = t;
}
return a;
}
void rmq()
{
for(int i=1;i<=n;i++)dp[i][0] = a[i];
for(int i=1;i<=log(n)/log(2);i++)
for(int j=1;j+(1<<i)-1<=n;j++)
dp[j][i] = gcd(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
}
int query(int l,int r)
{
int pre = log(r-l+1)/log(2);
return gcd(dp[l][pre],dp[r-(1<<pre)+1][pre]);
}
void solve()
{
for(int i=1;i<=n;i++)
{
int prePo = i;
int preGCD = a[i];
while(prePo<=n)
{
int l = prePo,r = n,ans = prePo;
while(l<=r)
{
int mid = (l+r)/2;
int st = query(i,mid);
if(st<preGCD)r = mid-1;
else {
if(st==preGCD)ans = mid;
l = mid + 1;
}
}
mp[preGCD] += (ans-prePo+1);
prePo = ans+1;
preGCD = gcd(preGCD,a[prePo]);
}
}
}
int main()
{
int t;
scanf("%d",&t);
int i1 = 1;
while(t--)
{
mp.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d",&m);
rmq();
solve();
printf("Case #%d:\n",i1);
i1++;
while(m--)
{
int l,r;
scanf("%d %d",&l,&r);
int pre = query(l,r);
printf("%d %I64d\n",pre,mp[pre]);
}
}
return 0;
}