zoukankan      html  css  js  c++  java
  • 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();
    }
    
    
  • 相关阅读:
    [mysql]修改 mysql 数据库端口
    [Angular]基础饼图之我如何将鼠标显示内容的数字 " 1" 去掉
    大三总结
    有符号8位整数的冒泡排序
    康托逆展开
    判断计算机是大端还是小端存储方式及分析
    C语言细节——献给入门者(三)
    C语言复杂声明
    病毒篇
    C语言细节——献给初学者(二)
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11508422.html
Copyright © 2011-2022 走看看