题解报告——数列

数列(queue)


时间限制: 3000 ms         内存限制: 65536 KB

【题目描述】

一个简单的数列问题,给定一个长度为nn的数列,求这样的三个元素a1,a2,a3a1,a2,a3的个数,满足ai<aj>akai<aj>ak,且i<j<ki<j<k。

【输入】

第一行一个整数n(1n50000)n(1≤n≤50000)。

接下来nn行,每行一个元素ai(0ai32767)ai(0≤ai≤32767)。

 

【输出】

输出一行一个整数,表示满足ai<aj>akai<aj>ak的个数。

【输入样例】

5
1
2
3
4
1

【输出样例】

6

【提示】

【数据范围】

对于30%的输入数据n200n≤200;

对于80%的输入数据n10000n≤10000。


 

【思路分析】

这道题很显然是一道求逆序对的题,那么求逆序对的方法很多,最好写也是很好理解的就是归并排序,但是发现这道题用归并没思路,因为并不知道如何用归并求出每一项的逆序对个数(可能是我太菜了)所以我就写了一个线段树的逆序对,我们这里还是解释一下如何用线段树求逆序对,我们每次插入一个数之后,我们就查询这个数之后的线段树中有多少个数已经被插入了,因为在这个数之后的数一定大于这个数,并且在它之前插入,那么一定就是逆序对了,所以就实现了线段树查逆序对。

那么了解之后,我们就可以用线段树查询了,其实发现这有3对,其实就是顺着求一遍逆序对,再反着求一遍逆序对,然后将当前数两次查到的个数相乘就可以求出以每个数为中心的3组数对了。

【代码实现】

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 struct sd{
 7     int l,r,num,son[2];
 8 }tree[150767];
 9 int sum=0;
10 int root=1;
11 const int lr=32777;
12 long long ans;
13 int len1[500005],len2[500005];
14 void build(int &v,int l1,int r1)
15 {
16     sum++;v=sum;
17     tree[v].l=l1,tree[v].r=r1,tree[v].num=0;
18     if(l1==r1)
19     {
20         tree[v].num=0;
21         return;
22     }
23     int mid=(l1+r1)/2;
24     build(tree[v].son[0],l1,mid);
25     build(tree[v].son[1],mid+1,r1);
26 }
27 int dfs(int v,int l1,int r1)
28 {
29     if(r1<l1) return 0;
30     if(tree[v].l==l1&&tree[v].r==r1)
31     return tree[v].num;
32     int mid=(tree[v].l+tree[v].r)/2;
33     if(r1<=mid)
34     return dfs(tree[v].son[0],l1,r1);
35     else
36     if(l1>mid)
37     return dfs(tree[v].son[1],l1,r1);
38     else
39     return dfs(tree[v].son[0],l1,mid)+dfs(tree[v].son[1],mid+1,r1);
40 }
41 void add(int key,int v,int l,int r,int orz,int id)
42 {
43     if(l==r&&l==key)
44     {
45         tree[v].num++;
46         if(orz==1)
47         len1[id]=dfs(1,0,l-1);
48         else
49         len2[id]=dfs(1,0,l-1);
50         return;
51     }
52     int mid=(l+r)/2;
53     if(key<=mid)
54     add(key,tree[v].son[0],l,mid,orz,id);
55     else
56     add(key,tree[v].son[1],mid+1,r,orz,id);
57     tree[v].num=tree[tree[v].son[0]].num+tree[tree[v].son[1]].num;
58 }
59 int a[500005];
60 int main()
61 {
62     int n;
63     scanf("%d",&n);
64     build(root,0,lr);
65     for(int i=1;i<=n;i++)
66     {
67         scanf("%d",&a[i]);
68     }
69     for(int i=1;i<=n;i++)
70     add(a[i],1,0,lr,1,i);
71     root=1,sum=0;
72     build(root,0,lr);
73     for(int i=n;i>=1;i--)
74     {
75         add(a[i],1,0,lr,2,i);
76     }
77     ans=0;
78     for(int i=1;i<=n;i++)
79     {
80         ans=(ans+(len1[i]*len2[i])%mod)%mod;
81     }
82     printf("%lld",ans);
83     return 0;
84 }

 

posted @ 2018-03-26 21:15  genius777  阅读(202)  评论(0编辑  收藏  举报