zoukankan      html  css  js  c++  java
  • hdu 5273 Dylans loves sequence 逆序数简单递推

    Dylans loves sequence

    Time Limit: 20 Sec

    Memory Limit: 256 MB

    题目连接

    http://acm.hdu.edu.cn/showproblem.php?pid=5273

    Description

    Dylans得到了N个数a[1]...a[N]。
    有Q个问题,每个问题形如(L,R)
    他需要求出L−R这些数中的逆序对个数。
    更加正式地,他需要求出二元组(x,y)的个数,使得L≤x,y≤R且x<y且a[x]>a[y]

    Input

    第一行有两个数N和Q。
    第二行给出N个数字a[1]...a[N]。
    接下来的Q行,每行给出两个数L,R。

    N≤1000,Q≤100000,L≤R,1≤a[i]≤231−1

    Output

    对于每个询问,输出逆序对个数。

    Sample Input

    3 2
    3 2 1
    1 2
    1 3

    Sample Output

    1
    3

    HINT

    题意

    题解:

    N只有1000,于是想怎么来就怎么来。
    最容易想到的是枚举开头,然后Nlog(N)时间里去算逆序对,用一个树状数组维护。
    (可惜BC不给卡。。。呜呜呜)
    仔细一想发现可以很简单地做到N2.
    设ans[l][r]为l∼r的逆序对数量。首先我们暴力地先算好ans[1][1..N]。
    然后i从2∼N枚举,每次计算从i开始的逆序对。
    那么ans[i][j]比ans[i−1][j]少了什么呢?没错,少了a[i−1]这个数的贡献。
    我们再开一个累加器cnt。枚举j从i∼N,如果a[i−1]和a[j]产生逆序对就cnt[j]=−1
    然后我们从右往左累加cnt(因为贡献是前缀和性质的)
    最后ans[i][j]=ans[i−1][j]+cnt[j]。
    预处理完所有的答案就可以O(1)的询问啦。

    代码

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <sstream>
    #include <queue>
    #include <typeinfo>
    #include <fstream>
    #include <map>
    #include <stack>
    typedef long long ll;
    using namespace std;
    //freopen("D.in","r",stdin);
    //freopen("D.out","w",stdout);
    #define sspeed ios_base::sync_with_stdio(0);cin.tie(0)
    #define test freopen("test.txt","r",stdin)  
    #define maxn 2000001
    #define mod 10007
    #define eps 1e-9
    const int inf=0x3f3f3f3f;
    const ll infll = 0x3f3f3f3f3f3f3f3fLL;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    //**************************************************************************************
    
    int d[1005][1005];
    int sum[1005][1005];
    int a[1005];
    int main()
    {
        int n=read(),q=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                if(a[j]<a[i])
                    d[i][j]=d[i][j-1]+1;
                else d[i][j]=d[i][j-1];
            }
            for(int j=i-1;j>=1;j--)
            {
                if(a[j]>a[i])
                    d[i][j]=d[i][j+1]+1;
                else 
                    d[i][j]=d[i][j+1];
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
                sum[i][j]=sum[i][j-1]+d[j][i];
        }
        while(q--)
        {
            int x=read(),y=read();
            printf("%d
    ",sum[x][y]);
        }
    }
    复制代码
  • 相关阅读:
    十天冲刺第1天
    第十四周学习总结
    评价输入法
    第十三周学习总结
    第十二周学习总结
    失物招领平台10
    失物招领平台9
    失物招领平台8
    第十一周学习总结
    失物招领平台7
  • 原文地址:https://www.cnblogs.com/qscqesze/p/4591057.html
Copyright © 2011-2022 走看看