zoukankan      html  css  js  c++  java
  • [P1966][NOIP2013T2] 火柴排队 (求逆序对+归并排序/树状数组)

    题意:题目给出两个等长的序列,求交换两个序列的最小次数,使两个序列之间的值满足 sum(ai-bi)^2 最小;

    解法:归并排序/树状数组+求逆序对

    1.归并排序/树状数组:这两种方式都是可以较快地求出逆序对个数

    2.求逆序对:因为只有当两个序列相对的数值都是其本序列中的相同等级的数,才能使等式最小。而移动两个序列的同一个数相当于没有移动,故题目可转化为将一个序列转变成为另一个序列的最小移动次数。此时不难看出 a序列转变为 b序列的最小移动次数就是 a的逆序对个数;

    下面给出树状数组求逆序对的代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cstdlib>
    #include<ctime>
    #define ll long long
    using namespace std;
    const int N = 100086;
    const int mod = 99999997;
    
    int n;
    struct node{
    	int sum,idx;
    }a[N],b[N],c[N];
    ll ans=0,d[N];
    
    int lowbit(int x){
    	return x&-x;
    }
    
    void add(int x,int k){
    	while(x<=n){
    		d[x]+=k;
    		d[x]%=mod;
    		x+=lowbit(x);
    	}
    }
    
    int query(int x){
    	int rel=0;
    	while(x){
    		rel+=d[x];
    		x-=lowbit(x);
    	}
    	return rel;
    }
    
    bool cmp(node x,node y){
    	return x.sum<y.sum;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i].sum),a[i].idx=i;
    	for(int i=1;i<=n;i++) scanf("%d",&b[i].sum),b[i].idx=i;
    	sort(a+1,a+1+n,cmp);
    	sort(b+1,b+1+n,cmp);
    	for(int i=1;i<=n;i++) c[i].sum=a[i].idx,c[i].idx=b[i].idx;
    	sort(c+1,c+1+n,cmp);
    	for(int i=1;i<=n;i++){
    		add(c[i].idx,1);
    		ans+=i-query(c[i].idx);
    		ans%=mod;
    	}
    	printf("%lld",ans%mod);
    	return 0;
    }
  • 相关阅读:
    RayTracing练习
    聚类方法总结
    Mysql、SqlServer和Oracle 添加修改删除字段
    gridview增加thead 和tbody
    数据库设计的三大范式
    c#+sql事务
    gridview应用
    DOS命令大全 IIS命令大全 SQL命令大全……
    TFS
    C#.NET官方类库Json序列化,反序列化
  • 原文地址:https://www.cnblogs.com/nnezgy/p/11366297.html
Copyright © 2011-2022 走看看