NOIP2013 Day1 T2 火柴排队 (贪心-逆序对-线段树)洛谷P1966
题目描述
涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2
其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
输入输出格式
输入格式:输入文件为 match.in。
共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出格式:输出文件为 match.out。
输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
输入输出样例
4 2 3 1 4 3 2 1 4
1
4 1 3 4 2 1 7 2 4
2
说明
【输入输出样例说明1】
最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。
【输入输出样例说明2】
最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。
【数据范围】
对于 10%的数据, 1 ≤ n ≤ 10;
对于 30%的数据,1 ≤ n ≤ 100;
对于 60%的数据,1 ≤ n ≤ 1,000;
对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ maxlongint
对于这道题,可以采用一个贪心的手段 :
所以我们可以知道,当第一盒火柴和第二盒火柴(即x[ ] y[ ] 两个数组)的排名相吻合时,可以得到题目中所说的最小距离;
所以我们可以输入时,既保存数值,又保存在原排列里的下标;这样可以进行一遍结构体的排序(按照数值排序),之后可以用两个结构体数组中保存的原排列的下标求逆序对数量,就可以知道我一共要交换多少次来使原排列达到目标序列;
之后套线段树求逆序对即可;
下面上代码,但这套代码是模板形成的,并不是特意为这道题而创造的,所以看上去可能有些困难;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5 #include<cstring> 6 #include<string> 7 #include<algorithm> 8 #include<bitset> 9 using namespace std; 10 const int MAXN=500005; 11 const int mod=99999997; 12 struct segtree{ 13 int l,ls,r,rs; 14 int data,lazy; 15 }t[MAXN*4];//线段树 16 struct node{ 17 int v,id; 18 friend bool operator < (node a,node b){ 19 return a.v<b.v; 20 } 21 }x[MAXN],y[MAXN]; //存储排列 22 int rt,cnt=0; 23 int a[MAXN]; 24 int n,m,k; 25 int s[MAXN]; 26 int read() 27 { 28 int x=0,f=1;char ch=getchar(); 29 while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} 30 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 31 return x*f; 32 } 33 void pushup(int cur) 34 { 35 int lson=t[cur].ls,rson=t[cur].rs; 36 t[cur].data=(t[lson].data+t[rson].data)%mod; 37 t[cur].l=t[lson].l; 38 t[cur].r=t[rson].r; 39 return ; 40 } 41 void build(int l,int r,int cur) 42 { 43 if(l==r){ 44 t[cur].ls=t[cur].rs=-1; 45 t[cur].l=t[cur].r=l; 46 t[cur].data=a[l]; 47 return ; 48 } 49 int mid=(l+r)>>1; 50 t[cur].ls=cnt++;t[cur].rs=cnt++; 51 build(l,mid,t[cur].ls);build(mid+1,r,t[cur].rs); 52 pushup(cur); 53 } 54 void update(int l,int r,int c,int cur) 55 { 56 if(t[cur].l==t[cur].r){ 57 t[cur].data++; 58 t[cur].data%=mod; 59 return ; 60 } 61 int mid=(t[cur].l+t[cur].r)>>1; 62 if(c<=mid) update(l,r,c,t[cur].ls); 63 else update(l,r,c,t[cur].rs); 64 pushup(cur); 65 return ; 66 } 67 int query(int l,int r,int cur,int c,int d) 68 { 69 if(c<=t[cur].l&&t[cur].r<=d){ 70 return t[cur].data; 71 } 72 int mid=(t[cur].l+t[cur].r)>>1; 73 if(d<=mid) return query(l,r,t[cur].ls,c,d); 74 else if(mid<c) return query(l,r,t[cur].rs,c,d); 75 return (query(l,r,t[cur].ls,c,mid)+query(l,r,t[cur].rs,mid+1,d))%mod; 76 } 77 int main() 78 { 79 rt=cnt++; 80 n=read(); 81 for(int i=1;i<=n;i++){ 82 x[i].v=read();x[i].id=i; 83 } 84 for(int i=1;i<=n;i++){ 85 y[i].v=read();y[i].id=i; 86 } 87 sort(x+1,x+n+1); 88 sort(y+1,y+n+1); 89 for(int i=1;i<=n;i++){ 90 s[x[i].id]=y[i].id; 91 } 92 int ans=0; 93 build(1,n,rt); 94 for(int i=1;i<=n;i++){ 95 if(s[i]!=n) ans+=query(1,n,rt,s[i]+1,n); 96 update(1,n,s[i],rt); 97 ans%=mod; 98 } 99 cout<<ans<<endl; 100 return 0; 101 }