noip2013提高组day1第二题火柴排队

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2013提高组day1第二题火柴排队相关的知识,希望对你有一定的参考价值。

各路大侠能否解释一下noip2013提高组day1第二题火柴排队怎么做,附上C语言代码更好!万分感谢

首先 先了解排序不等式 可证明 只有第一列的第i大火柴和第二列的第i大火柴在一起的时候 才会符合要求

然后思路就很清晰了 你有两条路:
暴力之 先快排一个 然后用二分查找 调换 据说这么做就有七十分了真是丧心病狂.....如果你更蛋疼一点的话 可以试试看用 stl模版中的vector 没准能过ac.......没准

正解方法 先对两个排序 然后求逆序对.......这么说可能太笼统 举个例子
设 第一个序列是32145 第二个序列是52143
第二个序列排成第一个,那么相当于第二个序列中
5应当排第5个
2应当排第2个
1应当排第3个
4应当排第4个
3应当排第1个
于是就是求52341的逆序对,7个
逆序对和快排你一定都会打了 那就这样吧...
提供c++版本ac代码.........

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int d[1000001];
long long ans=0;
void stablesort(int *a,int l,int mid,int r)

int i=l,j=mid+1,k=l;
while (i<=mid && j<=r)
if (a[i]<=a[j]) d[k++]=a[i++];
else d[k++]=a[j++]; ans+=mid+1-i;ans=ans%99999997;
while (i<=mid)
d[k++]=a[i++];
while (j<=r)
d[k++]=a[j++];
for (int q=l;q<=r;q++) a[q]=d[q];


void merge(int *a,int l,int r)

if (l<r)

int mid=(l+r)/2;
merge(a,l,mid);
merge(a,mid+1,r);
stablesort(a,l,mid,r);



int n,c[1000001];
struct data
int xx,yy;a[1000001],b[1000001];

inline int cmp(const void *a,const void *b)

if ( (*(data *)a) .xx < (*(data *)b) . xx )
return 1;
else return -1;


int main()

scanf("%d",&n);
for (int q=0;q<n;q++) scanf("%d",&a[q].xx);a[q].yy=q;
for (int q=0;q<n;q++) scanf("%d",&b[q].xx);b[q].yy=q;
qsort(a,n,sizeof(data),cmp);
qsort(b,n,sizeof(data),cmp);

for (int q=0;q<n;q++)
c[b[q].yy]=a[q].yy;
merge(c,0,n-1);
printf("%d",ans);
//system("pause");
return 0;

(因为我只会c++)
参考技术A 首先贪心只有第一列的第i大火柴和第二列的第i大火柴在一起的时候才会符合要求。

那要如何求距离呢??用逆序对。
用树状数组求出逆序对。
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<ctype.h>
#include<ctime>
#include<set>
#include<map>
#include<memory.h>
#include<cstring>
#include<iostream>
#include<fstream>
#include<vector>
#include<functional>
#include<queue>
#include<cassert>
#include<numeric>
#include<utility>
#include<deque>
#include<stack>
#include<bitset>
#include<list>
#include<iomanip>
#include<stdexcept>
#include<complex>
#include<iterator>
#define x first
#define y second
#define mp make_pair
using namespace std;
const int MAX=(1<<30);
pair<int,int>q[100001],q1[100001];
int pp[100001],s[100001];
int i,j,k,m,n;
const int mod=99999997;
int lowbit(int x)

return x&(-x);

int sum(int x)

int su=0;
while(x)

x-=lowbit(x);
su+=s[x],su%=mod;

return su;

int add(int x)

while(x<=n)

s[x]++,s[x]%=mod;
x+=lowbit(x);

return 0;

int main()

cin>>n;
for(i=1;i<=n;i++)
scanf("%d",&k),
q[i]=mp(k,i);
for(i=1;i<=n;i++)
scanf("%d",&k),
q1[i]=mp(k,i);
sort(q+1,q+n+1);
sort(q1+1,q1+n+1);
for(i=1;i<=n;i++)
pp[q[i].y]=q1[i].y;
for(i=n;i>0;i--)
m+=sum(pp[i])%mod,m%=mod,add(pp[i]+1);
cout<<m<<endl;
return 0;

NOIP2013提高组火柴排队

https://www.luogu.org/problem/show?pid=1966

Σ(ai-bi)2=Σai2+Σbi2-2Σai*bi,要使Σ(ai-bi)2最小,则需2Σai*bi最大。

由排序不等式可知两列数字里第一大与第一大对应,第二大与第二大对应,……,第k大与第k大对应,……,第n大与第n大对应时,Σai*bi最大。

故先将第一列每个数字映射到第二列排名相同的数字,再求需要交换的次数,也就是逆序对的个数。

#include <algorithm>
#include <iostream>
#include <vector>
#define maxn 100005
typedef long long llint;
using namespace std;
int n;
llint tmp[maxn], sorted[maxn], cnt = 0;
void merge_sort(int l, int r)
{
    if (l == r)
        return;

    int mid = (l + r) / 2;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);

    int p1 = l, p2 = mid + 1, p = l;
    while (p1 <= mid && p2 <= r)
    {
        if (sorted[p1] <= sorted[p2])
            tmp[p++] = sorted[p1++];
        else
        {
            cnt = (cnt + (mid - p1 + 1)) % 99999997;
            tmp[p++] = sorted[p2++];
        }
    }

    while (p1 <= mid)
        tmp[p++] = sorted[p1++];
    while (p2 <= r)
        tmp[p++] = sorted[p2++];

    for (int i = l; i <= r; i++)
        sorted[i] = tmp[i];
}
template <class T> void print(T *p)
{
    for (int i = 1; i <= n; i++)
        cout << p[i] <<  ; 
    cout << endl;
}
pair<llint, llint> a[maxn], b[maxn];
int rnk[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].first;
        a[i].second = i; 
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i].first;
        b[i].second = i; 
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);
    
    for (int i = 1; i <= n; i++)
        sorted[a[i].second] = b[i].second; // 将第一列排第i名的项与第二列排第i名的项对应
    merge_sort(1, n);
    cout << cnt << endl;
    return 0;
}

 

以上是关于noip2013提高组day1第二题火柴排队的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2013提高组火柴排队

刷提总结——火柴排队(NOIP2013)

Vijos P1496 火柴棒等式 NOIP2008提高组第二题

Codevs 3286 火柴排队 2013年NOIP全国联赛提高组 树状数组,逆序对

[NOIP2013提高组]火柴排队

noip提高组2013 火柴排队