题解
- 对于序列进行第一次划分后,以后的每次翻转都是两个数
- 为什么呢?
- 因为对于第一次翻转后会形成这样的一个序列:a1、a2...ai、b1、b2...bj、c1、c2...ck...
- 会形成若干个连续上升序列
- 考虑相邻的两个部分,ai与b1相邻
- 如果ai<b1的话,也就是说明这两个序列都是严格上升的,如果不是的话,就要进行翻转
- 因为ai-1<ai、b1<b2
- 所以以后的每次翻转都只用翻转两个相邻的逆序对
- 求逆序对可以用树状数组,那么对于第一次翻转,直接模拟可以得到
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <cstring>
4 using namespace std;
5 const long long inf=1000000000;
6 long long n,a[100010],mx,l,sum[100010];
7 long long ans;
8 long long getsum(long long x)
9 {
10 long long num=0;
11 while (x>0)
12 {
13 num+=sum[x];
14 x-=x&-x;
15 }
16 return num;
17 }
18 void update(long long x)
19 {
20 while (x<=n)
21 {
22 sum[x]++;
23 x+=x&-x;
24 }
25 }
26 void swap(long long l,long long r)
27 {
28 long long b[100010];
29 for (long long i=l;i<=r;i++) b[i]=a[r-i+l];
30 for (long long i=l;i<=r;i++) a[i]=b[i];
31 }
32 int main()
33 {
34 scanf("%lld",&n);
35 for (long long i=1;i<=n;i++) scanf("%lld",&a[i]);
36 mx=inf; l=1;
37 for (long long i=1;i<=n;i++)
38 {
39 if (mx<a[i])
40 {
41 if (l!=i-1)
42 {
43 ans++;
44 swap(l,i-1);
45 mx=a[i]; l=i;
46 }
47 }
48 else mx=a[i];
49 }
50 if (l<n) swap(l,n),ans++;
51 for (long long i=n;i>=1;i--)
52 {
53 ans+=getsum(a[i]);
54 update(a[i]);
55 }
56 printf("%lld",ans);
57 return 0;
58 }