题解 CF475D 【CGCDSSQ】

今天学习了分治之后,做ppt中间的一道题,没错,就是这道^_^

首先

我们先来看一下题,题目中让我们求的是一段区间的gcd为x的对数有多少。

我们这样考虑一下,当我们的区间的数的个数越多,我们的gcd一定不会比原来的gcd大。
所以,我们就可以的到一个单调不减gcd序列。 这样我们就可以预处理出所有的gcd,这样我们就可以直接的出答案。
因为一个数x,它的gcd的个数一定不会超过 logxlogxlogx ,所以我们就可以进行分治,统计个数,分为左右两部分,两部分分别进行暴力计算,,对于中间的部分,由于两者的答案互不影响,所以我们使用乘法原理,这样,我们就可以计算出跨mid的答案。

其实,这就是分治的思想的体现,

就像这张图一样

 

(看起来还是可以的吧)
将所求的的问题划分为两部分,最后在反回的时候,将答案进行一系列的操作,最后求得答案。
这就是分治在题中的思想运用。 代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<vector>
 6 #include<map>
 7 using namespace std;
 8 template<typename type>
 9 void scan(type &x){
10     type f=1;x=0;char s=getchar();
11     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
12     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
13     x*=f;
14 }
15 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
16 #define ll long long
17 const int N=1e5+7;
18 ll a[N],n,m;
19 vector <pair<int,int> >v[2];//分别记录左右两部分的答案
20 map <int,ll>ans;//统计答案
21 void solve(int l,int r){
22     if(l==r){
23         ans[a[l]]++;//如果l==r显然
24         return ;
25     }
26     int mid=(l+r)>>1;
27     solve(l,mid);solve(mid+1,r);
28     v[1].clear();v[0].clear();
29     int last=a[mid],now=a[mid],cnt=0;//统计左半部分
30     for(int i=mid;i>=l;i--){
31         now=gcd(now,a[i]);
32         if(last!=now){//如果gcd有变化,进行更新
33             v[0].push_back(make_pair(last,cnt));
34             cnt=1;
35             last=now;
36         }else cnt++;//统计个数
37     }v[0].push_back(make_pair(last,cnt));
38     last=now=a[mid+1],cnt=0;
39     for(int i=mid+1;i<=r;i++){//同理,右半部分
40         now=gcd(now,a[i]);
41         if(now!=last){
42             v[1].push_back(make_pair(last,cnt));
43             cnt=1;
44             last=now;
45         }else cnt++;
46     }v[1].push_back(make_pair(last,cnt));
47     for(int i=0;i<v[0].size();i++){
48         for(int j=0;j<v[1].size();j++){//跨mid答案统计
49             ans[gcd(v[0][i].first,v[1][j].first)]+=1LL*v[0][i].second*v[1][j].second;
50         }
51     }
52 }
53 int main(){
54     scan(n);
55     for(int i=1;i<=n;i++){
56         scan(a[i]);
57     }
58     solve (1,n);
59     scan(m);
60     while(m--){
61         int x;
62         scan(x);
63         printf("%lld\n",ans[x]);
64     }
65 }

这道题就讲到这里了,有什么问题希望大家可以提出。

posted @ 2019-07-24 10:37  惜时如金  阅读(263)  评论(0编辑  收藏  举报