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]
有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]); } }