LOJ2609. NOIP2013 火柴排队 【树状数组】
LOJ2609. NOIP2013 火柴排队
题目大意:
给你两个数列,定义权值∑i=1(ai−bi)^2
问最少的操作次数,最小化权值
首先需要发现几个性质
- 最小权值满足任意i,j不存在ai>aj,bi<bj
- 只需要改变一个序列的顺序就足够了
- 把一个序列排序成有序的最少操作次数是逆序对个数
然后就可以随便做了
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100010 4 #define Mod 99999997 5 struct Node{int val,id;}a[N],b[N]; 6 int n,match[N]; 7 bool cmp(Node a,Node b){return a.val<b.val;} 8 int t[N]; 9 int add(int a,int b){return (a+b)%Mod;} 10 void add(int x){while(x<=n)t[x]++,x+=x&(-x);} 11 int query(int x){int res=0;while(x)res=add(res,t[x]),x-=x&(-x);return res;} 12 int main(){ 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++)a[i].id=b[i].id=i; 15 for(int i=1;i<=n;i++)scanf("%d",&a[i].val); 16 for(int i=1;i<=n;i++)scanf("%d",&b[i].val); 17 sort(a+1,a+n+1,cmp); 18 sort(b+1,b+n+1,cmp); 19 for(int i=1;i<=n;i++)match[a[i].id]=b[i].id; 20 int ans=0; 21 for(int i=n;i>=1;i--){ 22 ans=add(ans,query(match[i])); 23 add(match[i]); 24 } 25 printf("%d",ans); 26 return 0; 27 }