• 题解 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
    ",ans[x]);
    64     }
    65 }

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

  • 相关阅读:
    hack games
    Metasploit 使用简介
    Back Track5学习笔记
    Metasploit没有db_autopwn命令的解决办法
    BT5 set_config各个选项的配置
    c# 截屏
    c#图像计算知识
    游戏代码
    Google Protocol Buffers (一个客户端与服务器协议生成工具)
    WinPcap抓取数据包
  • 原文地址:https://www.cnblogs.com/xishirujin/p/11236434.html
Copyright © 2020-2023  润新知