手套
【问题描述】
你现在有N对手套,但是你不小心把它们弄乱了,需要把它们整理一下。N对手套被一字排开,每只手套都有一个颜色,被记为0~N-1,你打算通过交换把每对手套都排在一起。由于手套比较多,你每次只能交换相邻两个手套。请你计算最少要交换几次才能把手套排整齐。
【输入】
输入第一行一个N,表示手套对数。
第二行有2N个整数,描述了手套的颜色。每个数都在0~N-1之间,且每个数字都会出现恰好两次。
【输出】
一行,包含一个数,表示最少交换次数。
【输入输出样例】
gloves.in | gloves.out |
2 0 1 0 1 | 1 |
【输入输出样例说明】
将中间两个手套交换过来,颜色序列变成0 0 1 1。
【数据规模与约定】
30%的数据N≤9;
60%的数据N≤1000;
100%的数据N≤200,000。
题目分析:答案就是逆序对的数量。写了个树状数组练个手,结果忘了开long long炸剩80……
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=200100;
const int oo=1000000001;
int bit[maxn];
int a[maxn<<1];
int id[maxn];
int n;
int Sum(int x)
{
int temp=0;
while (x)
{
temp+=bit[x];
x-=( x&(-x) );
}
return temp;
}
void Add(int x)
{
while (x<=n)
{
bit[x]++;
x+=( x&(-x) );
}
}
int main()
{
freopen("gloves.in","r",stdin);
freopen("gloves.out","w",stdout);
scanf("%d",&n);
int cur=0;
for (int i=0; i<n; i++) id[i]=oo;
for (int i=1; i<=(n<<1); i++)
{
int x;
scanf("%d",&x);
a[i]=x;
if ( id[x]==oo )
{
cur++;
id[x]=cur;
}
}
long long ans=0;
for (int i=1; i<=(n<<1); i++)
{
int x=a[i];
ans+=(long long)( Sum(n)-Sum( id[x] ) );
Add( id[x] );
}
cout<<ans;
return 0;
}