Codeforces Round #261 (Div. 2) D. Pashmak and Parmida's problem (树状数组求逆序数 变形)

题目链接

题意:给出数组A,定义f(l,r,x)为A[]的下标l到r之间,等于x的元素数。i和j符合f(1,i,a[i])>f(j,n,a[j]),求i和j的种类数。

我们可以用map预处理出 f(1, i, a[i]) 和 f(j, n, a[j]) ,记为s1[n], s2[n]。

这样就变成求满足 s1[i] > s[j], i < j 情况的数量了,你会发现跟求逆序对一样

分析:

做题的时候想到过逆序数,但是很快放弃了,还是理解不深刻吧,,,233.

看了这个博客以后才明白这些过程:http://www.cnblogs.com/yuiffy/p/3916512.html

使用树状数组统计小于某数的元素数量。

我们可以先把f(1,i,a[i])和f(j,n,a[j])写出来,观察一下,例如样例1:

n=7

A  1  2  1  1  2  2  1

R  4  3  3  2  2  1  1

L  1  1  2  3  2  3  4

其中A为给定的数组,Rj为f(j,n,a[j]),Li为f(1,i,a[i])。

对每个Li,我们要统计的其实就是符合(j>i,且Rj<Li)的Rj的个数。就是这个Li右边有多少个比它小的Rj。

这样我们可以用树状数组,把Rj各个数的数量全存到树状数组里,例如这个样例就是4有1个,3有2个,2有2个,1有2个。然后从左到右遍历Li,每次从树状数组里删掉Rj,并且求sum(Li-1),也就是树状数组中1~Li-1的和,也就是比Li小的元素个数。

例如这个样例,到L3时,树状数组里记了2个1和2个2(1个4和2个3在之前被删掉了),L3=2,则sum(L3-1)=sum(2)=1的数量+2的数量=3。ans+=3。

其实从左到右加一遍以后,树状数组是这个样子的:

下标 1  2  3  4

值    2  2  2  1

不能不说这个过程还是挺难想的

时间复杂度是O(n*log(n));

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #define LL __int64
 9 const int maxn = 1000000+10;
10 using namespace std;
11 int c[maxn], a[maxn], n;
12 
13 int lowbit(int x)
14 {
15     return x&(-x);
16 }
17 void add(int x,int d)
18 {
19     while(x <= n)
20     {
21         c[x] += d;
22         x +=lowbit(x);
23     }
24 }
25 LL sum(int x)
26 {
27     LL ret = 0;
28     while(x > 0)
29     {
30         ret += c[x];
31         x -= lowbit(x);
32     }
33     return ret;
34 }
35 void slove()
36 {
37     map<int, int>x, y;
38     LL ans = 0;
39     int i;
40     memset(c, 0, sizeof(c));
41 
42     for(i = 1; i <= n; i++)
43     {
44         scanf("%d", &a[i]);
45         x[a[i]] ++;
46         add(x[a[i]], 1);  //其实树状数组里的下标代表个数,数组里的数代表扫过去的依次产生的该个数的数量。
47     }
48     for(i = 1; i <= n; i++)
49     {
50         y[a[i]] ++; //要查找的数量++
51         add(x[a[i]], -1);  //依次把原来的-1
52         x[a[i]] --;  //x[]里也要减去
53         ans += sum(y[a[i]]-1); //求从1到 比当前的个数少一的个数的和。
54     }
55     printf("%I64d
", ans);
56 }
57 
58 int main()
59 {
60     while(~scanf("%d", &n))
61     {
62         slove();
63     }
64     return 0;
65 }
原文地址:https://www.cnblogs.com/bfshm/p/3916799.html