[NOIP2013]火柴排队
Posted QYP_2002
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }
以上是关于[NOIP2013]火柴排队的主要内容,如果未能解决你的问题,请参考以下文章