codeforces 261 D

题目链接:

解题报告:给出一个序列a1,a2,a3.........an,f(i , j ,x) ak 等于x的个数(i <= k <= j),令i < j,求有多少对 i 和 j 使得 f(1,i,ai) > f(j,n,aj)。

从左往右扫一遍这个序列,num1[i] 等于从1到i有多少个等于a[i]的,同理从右往左扫一遍得到num2[i],然后把从右往左扫的num2[i]的个数用一个树状数组维护,先全部加到树状数组里面去,然后从左往右扫一遍num1[i],每次判断在num2中有多少个小于num1[i]的数,同时判断完之后要把对应的num2[i]的个数减去1,因为这时候num1[i]的位置已经超过这个num2的位置了,所以以后的算个数的时候这个num2[i]不能算进去,应该删掉。用树状数组的目的就是为了能快速判断num2[i]中有多少个小于num1[i]的,这样可以做到在log2(n)的时间内完成查找和删除操作。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<map>
 5 #include<algorithm>
 6 using namespace std;
 7 #define LL long long
 8 #define maxn 1000005
 9 LL n,tot;
10 map<LL,LL> mp1,mp2;
11 LL a[maxn],num1[maxn],num2[maxn],num3[maxn];
12 LL tree[maxn];
13 LL find(LL d,int l,int r)
14 {
15     while(l < r)
16     {
17         int mid = (l + r) / 2;
18         if(d <= num1[mid]) r = mid;
19         else l = mid + 1;
20     }
21     if(num1[l] != d) return l - 1;
22     else return l;
23 }
24 void insert(int l,int d)
25 {
26     for(int i = l;i <= n;i += (-i & i))
27     tree[i] += d;
28 }
29 LL sum(int l)
30 {
31     LL tot = 0;
32     for(int i = l;i > 0;i -= (-i & i))
33     tot += tree[i];
34     return tot;
35 }
36 
37 int main()
38 {
39     
40     while(scanf("%lld",&n)!=EOF)
41     {
42         for(int i = 1;i <= n;++i)
43         scanf("%lld",&a[i]);
44         memset(tree,0,sizeof(tree));
45         memset(num1,0,sizeof(num1));
46         memset(num2,0,sizeof(num2));
47         mp1.clear();
48         mp2.clear();
49         for(int i  = 1;i <= n;++i)
50         {
51             if(mp1.insert(pair<LL,LL> (a[i],1)).second == 1)
52             num1[i] = 1;
53             else
54             {
55                 mp1[a[i]] = mp1[a[i]] + 1;
56                 num1[i] = mp1[a[i]];
57             }
58         }
59         for(int i = n;i >= 1;--i)
60         {
61             if(mp2.insert(pair<LL,LL> (a[i],1)).second == 1)
62             num2[i] = 1;
63             else
64             {
65                 mp2[a[i]] = mp2[a[i]] + 1;
66                 num2[i] = mp2[a[i]];
67             }
68         }
69         for(int i = 1;i <= n;++i)
70         insert(num2[i],1);
71         tot = 0;
72         for(int i = 1;i <= n;++i)
73         {
74             insert(num2[i],-1);
75             tot += sum(num1[i]-1);
76         }
77         printf("%lld
",tot);
78     }
79     return 0;
80 }
View Code
原文地址:https://www.cnblogs.com/xiaxiaosheng/p/3916290.html