zoukankan      html  css  js  c++  java
  • [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队

    Description

    涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2
    其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
    每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。

    输入格式:
    共三行,第一行包含一个整数 n,表示每盒中火柴的数目。
    第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
    第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

    输出格式:
    输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。

    Solution

    1.要是两列火柴距离最小,那么我们就应让所有的(ai-bi)^2最小,即ai与bi的差最小,考虑贪心,应该让在序列中从小到大排序后序号相同的数相减,因为如果两数列中两个数在各自数列中从小到大序号相等,那么如果这两个数不做差分别与另一个数做差,差的平方显然是要比原来大的。

    2.那么我们考虑如何将数列整理成想要的:我们建立一个新的数列,以离散后的第一个数列该项为下标,以离散后第二个数列对应的项为值建立,相当于以第一个数列为关键字排序第二个数列,然后跑一遍逆序对即可。

    树状数组求逆序对的方法参考我的博文:http://www.cnblogs.com/COLIN-LIGHTNING/p/8621294.html

    Code

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    int now[100100],c[100100],n,m,i,j,k;
    struct nums{
    	int num,d;
    }a1[100100],a2[100100];
    
    inline int rd(){
        int x=0;
        char c=getchar();
    	bool f=false;
    	while(!isdigit(c)){ 
    		if(c=='-') f=true;
    		c=getchar();
    	}
    	while(isdigit(c)){
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	return f?-x:x;
    }
    
    inline int lowbit(int x){return x&-x;}
    
    void add(int x){
    	while(x<=n){
    		c[x]+=1;
    		x+=lowbit(x);
    	}
    }
    
    int sum(int x){
    	int ret=0;
    	while(x>0){
    		ret+=c[x];
    		x-=lowbit(x);
    	}
    	return ret;
    }
    
    bool cmp(nums x,nums y){
    	return x.num<y.num;
    }
    int main(){
    	memset(c,0,sizeof(c));
    	n=rd();
    	for(i=1;i<=n;++i){
    		a1[i].num=rd();
    		a1[i].d=i;
    	}
    	for(i=1;i<=n;++i){
    		a2[i].num=rd();
    		a2[i].d=i;
    	}
    	sort(a1+1,a1+1+n,cmp);
    	sort(a2+1,a2+1+n,cmp);
    	for(i=1;i<=n;++i) now[a1[i].d]=a2[i].d;
    	long long ans=0;
    	for(i=n;i>0;--i){
    		add(now[i]);
    		ans=(ans+sum(now[i]-1))%99999997;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Jmail组件发送邮件说明ASP.NET
    五种常见的ASP.NET应用程序安全缺陷
    按比例生成缩略图
    光盘自动运行HTML页,Autorun文件写法
    页面全屏显示JS代码
    除去内容中的HTML代码方法
    JS函数学习(2)
    JS学习变量与基本语法(1)
    C#中Math.Round()实现中国式四舍五入
    (2) EFCore数据库上下文和模型(数据表)的配置
  • 原文地址:https://www.cnblogs.com/COLIN-LIGHTNING/p/8621855.html
Copyright © 2011-2022 走看看