• 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();
    }
    
    
  • 相关阅读:
    Leecode no.22 括号生成
    修改mysql数据库的时区
    Django 路由层之反向解析
    学习 Django 的几个教程网址
    leetcode周赛 242
    AcWing第二次热身赛
    AcWing夏季每日一题--最长公共子序列
    AcWIng夏季每日一题--序列最大收益
    leetcode周赛 241
    第十二届蓝桥杯C++ B组
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11508422.html
Copyright © 2020-2023  润新知