详细:view
题意:给定N个数,求有多少个区间【L,R】满足区间内所有数的gcd为X。
由题出发,面临两个问题:
1。对于10^5个数,如何快速求解每个子区间的gcd
2。对于达到10^9的数,如何知道它出现了多少次。
对于第二个问题,需要用map解决,map<int ,long long>,它相当于一个数组,其first 值与second值一一对应,用second记录其first值出现的次数。
而第一个问题,就需要利用gcd的性质,即区间长度越大,gcd就递减。而且10^5个数的不同的gcd值不会太多,所以就利用这一性质可以解决。类似于凑金币里用到的dp,思路特别简单。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define sf scanf
#define pf printf
#define FT first
#define SD second
typedef long long LL;
map<int,LL> ans;
map<int,LL> dp1,dp2;
int a[100005];
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main()
{
//freopen("in.txt","r",stdin);
int n;
sf("%d",&n);
for(int i=1;i<=n;i++)
sf("%d",&a[i]);
ans[a[1]]=1;
dp1[a[1]]=1;
map<int ,LL> ::iterator it;
for(int i=2;i<=n;i++)
{
ans[a[i]]++;
dp2[a[i]]++;
for(it=dp1.begin();it!=dp1.end();it++)
{
int v=gcd(a[i],it->FT);
dp2[v]+=it->SD;
ans[v]+=it->SD;
}
dp1.clear();
for(it=dp2.begin();it!=dp2.end();it++)
dp1[it->FT]=it->SD;
dp2.clear();
}
int Q,x;
sf("%d",&Q);
while(Q--)
{
sf("%d",&x);
cout<<ans[x]<<endl;
}
return 0;
}