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 取模的结果。

输入输出样例

输入样例#1:
4
2 3 1 4
3 2 1 4
输出样例#1:
1
输入样例#2:
4
1 3 4 2
1 7 2 4
输出样例#2:
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 } 
View Code

 

posted @ 2018-05-10 11:56  杜宇一声  阅读(189)  评论(0编辑  收藏  举报