E-寄CD?_2022广西师范大学暑期训练赛 (nowcoder.com)
题目描述
给你一个长度为 n 的序列 a, 接下来有 q 个 询问,
每个询问给出一个数 x, 你需要求出 gcd(al,al+1...ar)=x 的区间数量。
输入
1 5 2 1 2 3 4 5 1 2输出
11 1
ST表+二分做法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=200200,M=2002;
map<LL,LL> mp;
int n,q,a[N],f[N][20];
int query(int l,int r)
{
int k=log(r-l+1)/log(2);
return __gcd(f[l][k],f[r-(1<<k)+1][k]);
}
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
int T=1;
cin>>T;
while(T--)
{
mp.clear();
cin>>n>>q;
for(int i=1;i<=n;i++)
{
cin>>a[i];
f[i][0]=a[i];//f[i][0]就是它本身
}
for(int j=1;j<=21;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
f[i][j]=__gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//倍增预处理
}
}
for(int i=1;i<=n;i++)//枚举左端点
{
int j=i,num=a[i];
while(j<=n)
{
int l=j,r=n;
while(l<r)
{
int mid=(l+r+1)/2;
if(query(i,mid)==num) l=mid;
else r=mid-1;
}
mp[num]+=l-j+1;
j=l+1;
num=query(i,j);//更新gcd
}
}
while(q--)
{
int x;
cin>>x;
cout<<mp[x]<<endl;
}
}
return 0;
}