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\n",sum[x][y]);
    }
}

 

 

 

复制代码
posted @ 2015-06-20 21:27  qscqesze  阅读(445)  评论(0编辑  收藏  举报