• ACM-ICPC 2018 徐州赛区网络预赛 I. query 树状数组


    I. query

    题目链接:

    Problem Description

    Given a permutation (p) of length (n), you are asked to answer (m) queries, each query can be represented as a pair ((l ,r )), you need to find the number of pair ((i ,j)) such that (l le i < j le r) and (min(p_i,p_j) = gcd(p_i,p_j )).

    Input

    There is two integers (n(1 le n le 10^5)), (m(1 le m le 10^5)) in the first line, denoting the length of (p) and the number of queries.

    In the second line, there is a permutation of length (n), denoting the given permutation (p). It is guaranteed that (p) is a permutation of length (n).

    For the next (m) lines, each line contains two integer (l_i) and (r_i(1 le l_i le r_i le n)), denoting each query.

    Output

    For each query, print a single line containing only one integer which denotes the number of pair ((i,j)).

    样例输入

    3 2
    1 2 3
    1 3
    2 3

    样例输出

    2
    0

    题意

    给你一个序列,求很多段子区间((l ,r ))满足(l le i < j le r) and (min(p_i,p_j) = gcd(p_i,p_j )) 的个数。

    题解

    1.转化一下就是求一个区间有多少对满足一个是另一个的倍数。

    2.我们会发现这个是一个排列,每个数x的倍数个数为(frac{n}{x}),那么所有的倍数个数即为(sum_{i=1}^{n}frac{n}{i})(le nlog_{2}{n+1}))

    3.我们将所有倍数点对预处理出来,问题就变成了问一个区间有多少倍数点对同时存在。

    4.是不是很熟悉啦(不知道也没关系),我来细细讲解一下:

    • 先将区间按右端点从小到大排序,保证右端点单调递增
    • 那么起作用的就是左端点,这是我们碰到一个点就将它左边的所有是它约数以及倍数的位置权值全部+1,这样如果左边这个点在区间里,右端点必然也在区间里因为右端点单调递增。

    如果真的理解了的话想想按左端点从大到小也可以做,想想怎么做?

    其实这题是cf原题,网络赛时我不会做,然后竟然搜到了原题(还是有极其微小的差异),然后现学啦,哈哈哈。

    cf链接:codeforces 301D

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define INF 0x7f7f7f7f
    #define N 100050
    template<typename T>void read(T&x)
    {
        ll k=0; char c=getchar();
        x=0;
        while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
        if (c==EOF)exit(0);
        while(isdigit(c))x=x*10+c-'0',c=getchar();
        x=k?-x:x;
    }
    void read_char(char &c)
    {while(!isalpha(c=getchar())&&c!=EOF);}
    int n,m,a[N],p[N],c[N],ans[N];
    vector<int>vec[N];
    struct Query
    {
        int l,r,id;
        bool operator <(const Query b)const
            {return r<b.r;}
    }que[N];
    void change(int x){while(x<=n)c[x]++,x+=x&-x;}
    int ask(int x){int ans=0;while(x)ans+=c[x],x-=x&-x;return ans;}
    void work()
    {
        read(n); read(m);
        for(int i=1;i<=n;i++) read(a[i]),p[a[i]]=i;
        for(int i=1;i<=m;i++) read(que[i].l),read(que[i].r),que[i].id=i;
        for(int i=1;i<=n;i++)
        {
            for(int j=a[i]+a[i];j<=n;j+=a[i])
                if (i<p[j])vec[p[j]].push_back(i);
                else vec[i].push_back(p[j]);
        }
        sort(que+1,que+m+1);
        int r=0;
        for(int i=1;i<=m;i++)
        {
            for(int j=r+1;j<=que[i].r;j++)
                for(int k=0;k<vec[j].size();k++)change(vec[j][k]);
            r=que[i].r;
            ans[que[i].id]=ask(que[i].r)-ask(que[i].l-1);
        }
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        work();
    }
    
    
  • 相关阅读:
    EasyUI DataGrid及Pagination
    Easyui Datagrid的Rownumber行号显示问题
    Easyui控制combotree只能选择叶子节点
    Easyui datebox单击文本框显示日期选择
    EasyUI DataGrid可编辑单元格
    EasyUI获取DataGrid中某一列的所有值
    EasyUI DataGrid 多级表头设置
    EasyUI DataGrid 编辑单元格
    EasyUI combobox 加载JSON数据《一》
    EasyUI combobox 加载JSON数据
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11508422.html
Copyright © 2020-2023  润新知