Luogu | P1966 [NOIp 2013] 火柴排队 | 数据结构 | 树状数组
Description
涵涵有两盒火柴,每盒装有 $n$ 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:$\sum (a_i-b_i)^2$。
其中 $a_i$ 表示第一列火柴中第 $i$ 个火柴的高度,$b_i$ 表示第二列火柴中第 $i$ 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 $99,999,997$ 取模的结果。
Input Format
共三行,第一行包含一个整数 $n$,表示每盒中火柴的数目。
第二行有 $n$ 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 $n$ 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
Output Format
一个整数,表示最少交换次数对 $99,999,997$ 取模的结果。
Input Sample
Sample 01
4
2 3 1 4
3 2 1 4
Sample 02
4
1 3 4 2
1 7 2 4
Output Sample
Sample 01
1
Sample 02
2
Data Range
$1 \le N \le 10^5$,火柴高度在
long long
范围内。
Solution
考虑将距离的式子化开,无论 $a_i$ 和 $b_i$ 怎么选,最后总和里 $a_i^2$ 和 $b_i^2$ 都不会变,所以直接看 $-2ab$ 的部分。则题目要求 $\sum2ab$ 最大。数学方法可证得当 $A,B$ 两个序列均按相同(升序 / 降序)排序时值最大。
显然交换 $A$ 和交换 $B$ 等价,所以只考虑将 $B$ 作为基准映射 $A$ 之后交换 $A$。树状数组求逆序对。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define swap(x,y) {int t=x; x=y,y=t;}
#define wipe(x,y) memset(x,y,sizeof(x))
#define dbgIn(x) freopen(x".in","r+",stdin)
#define rep(x,y,z) for(int x=y,I=z;x<=I;++x)
#define dbgOut(x) freopen(x".out","w+",stdout)
#define file(x) freopen(x".in","r+",stdin); freopen(x".out","w+",stdout)
#define mod 99999997
#define lowbit(x) (x&(-x))
using std::sort;
using std::lower_bound;
typedef long long ll;
inline void Read(int &x){
x=0; char ch=0; while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return;
}
struct data{
int id;
ll val;
int ExceptedPosition;
friend bool operator < (data a,data b){
return a.val<b.val;
}
}A[100005],B[100005];
int N;
ll ans;
int BIT[100005];
ll pool[200005];
bool rec(data a,data b){
return a.id<b.id;
}
void BITModify(int u,int v){
for(;u<=N;u+=lowbit(u))
BIT[u]+=v;
return;
}
int BITQuery(int u){
int ret=0;
for(;u;u-=lowbit(u))
ret+=BIT[u];
return ret;
}
int BITQuery(int L,int R){
return BITQuery(R)-BITQuery(L-1);
}
int main(){
Read(N);
rep(i,1,N)
scanf("%lld",&A[i].val);
rep(i,1,N)
scanf("%lld",&B[i].val);
rep(i,1,N)
pool[i]=A[i].val;
rep(i,1,N)
pool[i+N]=B[i].val;
rep(i,1,N)
A[i].id=i,B[i].id=i;
sort(pool+1,pool+1+2*N);
rep(i,1,N)
A[i].val=lower_bound(pool+1,pool+1+2*N,A[i].val)-pool;
rep(i,1,N)
B[i].val=lower_bound(pool+1,pool+1+2*N,B[i].val)-pool;
sort(A+1,A+1+N);
sort(B+1,B+1+N);
rep(i,1,N)
A[i].ExceptedPosition=B[i].id;
sort(A+1,A+1+N,rec);
rep(i,1,N){
ans+=BITQuery(A[i].ExceptedPosition,N);
BITModify(A[i].ExceptedPosition,1);
}
printf("%lld\n",ans%mod);
return 0;
}