题意:
给定区间l~r,询问子区间中有多少个gcd与 这个区间gcd相等
思路:
rmq可以快速处理出l~r区间的gcd,区间gcd是一个收敛很快的非单调递增的,可以用二分处理出各个gcd的个数,之后再一次输出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int maxn=100010;
int dp[maxn][30];
map<int,long long> mp;
int a[maxn];
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
void ST(int n)
{
for(int i=1; i<=n; i++)
dp[i][0] = a[i];
for(int j =1; (1<<j)<=n; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++)
{
dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int i,int j)
{
int k=0;
while((1<<(k+1))<=j-i+1) k++;
return gcd(dp[i][k],dp[j-(1<<k)+1][k]);
}
int main()
{
int t;
scanf("%d",&t);
for(int cs=1; cs<=t; cs++)
{
mp.clear();
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
ST(n);
for(int i=1; i<=n; i++)
{
int l=i,r=n;
int num=a[i];
while(l<=n)
{
int lnow=l,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
int now=RMQ(i,mid);
if(now==num)
l=mid+1;
else
r=mid-1;
}
mp[num]+=(r-lnow+1);
num=gcd(num,a[l]);
}
}
int m;
scanf("%d",&m);
printf("Case #%d:\n",cs);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
int tmp=RMQ(l,r);
printf("%d %lld\n",tmp,mp[tmp]);
}
}
}