[NOIP2013]火柴排队

【题目描述】

思路{
  首先贪心地想,应该是小怼小,大怼大。即A(i)<=A(i+1),B(i)<=B(i+1),这是排序不等式
  证明它,我们需要使用和式恒等变换(感谢朱峰昊(朱哥)的大力支持){
    设A(i)<=A(i+1),B(i)<=B(i+1),证明:
      ∑A(i)*B(i)(顺序和)
      >=∑A(i)*B( j(i) )(乱序和)
      >=∑A(i)*B(n-i+1)(逆序和)
      其中j(i)为一个任意的对应关系。
      设S[i]=∑B(k)(k<=i),S'[i]=∑B(  j(k) );易知,S[i]<=S‘[i];又因为A(i)<=A(i+1)
      所以S[i]*(A[i+1]-A[i])>=S’[i]*(A[i+1]-A[i])
      ∑A(i)*B(i)=∑S[i]*(A[i+1]-A[i])(i<=n-1)+A[n]*B[n]
                   >=∑S‘[i]*(A[i+1]-A[i])(i<=n-1)+A[n]*B[n]
                   =∑A(i)*B( j(i) );
                             同理证得右边也成立,问题得证。
          }
  问题解的min为∑(A[i]-B[i])^2=∑A[i]^2+∑B[i]^2-2∑A(i)*B(i).
  前两项是恒定的,故后一项取最大即可,即为顺序和。
        可以统计出每个位置当前点所对应的下标pos[i]。首状态是位置依次递增的。
        而末状态为pos[i],pos[i+1]......pos[n];
        要统计多少步,不妨反过来考虑。
        由于交换两个数只改变这两个数所成的逆序对。
        反过来考虑,就是把一个存在逆序对的数组变成一个非严格上升的子序列,
        且每次交换操作只改变一对。
        那么,只需要用树状数组统计pos下标的逆序对就可以了。

}

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<queue>
 7 #include<ctime>
 8 #include<cmath>
 9 #include<list>
10 #include<deque>
11 #include<stack>
12 #include<map>
13 #include<set>
14 #define RG register
15 #define LL long long
16 #define dd double
17 #define maxx 200001
18 #define rs (o*2+1)
19 #define ls (o*2)
20 #define mid ((L+R)/2)
21 #define MOD 99999997
22 #define low(k) (k)&(-k)
23 using namespace std;
24 LL n;LL ans;
25 struct matrix{
26 LL num,pos;
27   matrix () {}
28   matrix(int nn,int pp):num(nn),pos(pp) {}
29 };
30 bool comp(const matrix & a,const matrix & b){return a.num<b.num;}
31 bool comp1(const matrix & a,const matrix & b){return a.pos<b.pos;}
32 matrix a[maxx],b[maxx];LL t[maxx];int tree[maxx];
33 void Insert(LL p){for(RG LL i=p;i<=n;i+=low(i))tree[i]++;}
34 LL ask(LL p){LL sum=0;for(RG int i=p;i;i-=low(i))sum+=tree[i];return sum;}
35 int main(){
36   freopen("MatchNOIP2013.in","r",stdin);
37   freopen("MatchNOIP2013.out","w",stdout);
38   scanf("%lld",&n);LL x;
39   for(RG int i=1;i<=n;++i)scanf("%lld",&x),a[i]=matrix(x,i);
40   for(RG int i=1;i<=n;++i)scanf("%lld",&x),b[i]=matrix(x,i);
41   sort(a+1,a+n+1,comp);sort(b+1,b+n+1,comp);
42   for(RG int i=1;i<=n;++i)t[a[i].pos]=b[i].pos;
43   for(RG int i=1;i<=n;++i){
44     Insert(t[i]);
45     ans+=(i-ask(t[i])+MOD)%MOD;
46     ans%=MOD;
47   }
48   printf("%lld",ans);return 0;
49 }
原文地址:https://www.cnblogs.com/zzmmm/p/6898454.html