http://acm.hdu.edu.cn/showproblem.php?pid=1394
題意:給你一個有 n 個 小於 n 且不重複的數組成的序列,每次將序列最前面的數字移動到序列的最後面,求移動過程中序列的最小的逆序對。
思路:這題數據比較小可以先暴力出原始序列的逆序對,然後每次將最前的數移動到最後逆序對就會變成 ans = ans - num[0] + n - num[0] - 1。
這題可以暴力, 樹狀數組, 歸併排序, 線段樹, Splay樹來求解。
暴力(187ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 5005;
int n;
int ary[maxn];
int Reverse()
{
int ret = 0;
for(int i = 0; i < n; i++){
for(int k = i +1; k < n; k++){
ret += (ary[i] > ary[k]);
}
}
return ret;
}
int main()
{
while(~scanf("%d", &n) && n){
for(int i = 0; i < n; i++){
scanf("%d", &ary[i]);
}
int ans = Reverse();
int res = ans;
for(int i = 0; i < n; i++){
ans = ans - ary[i] + n - ary[i] - 1;
res = res < ans ? res : ans;
}
printf("%d\n", res);
}
return 0;
}
樹狀數組(46ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 5005;
int n;
int ary[maxn];
int tr[maxn];
int fun(int x){
return x & (-x);
}
void Insert(int pos)
{
while(pos <= n){
tr[pos]++;
pos += fun(pos);
}
}
int Query(int l, int r)
{
int res = 0;
while(r){
res += tr[r];
r -= fun(r);
}
l--;
while(l){
res -= tr[l];
l -= fun(l);
}
return res;
}
int main()
{
while(~scanf("%d", &n) && n){
int ans = 0;
memset(tr, 0, sizeof(tr));
for(int i = 0; i < n; i++){
scanf("%d", &ary[i]);
Insert(ary[i] + 1);
ans += Query(ary[i] + 2, n);
}
int res = ans;
for(int i = 0; i < n; i++){
ans = ans - ary[i] + n - ary[i] - 1;
res = res < ans ? res : ans;
}
printf("%d\n", res);
}
return 0;
}
歸併排序(46ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 5005;
int n;
int temp[maxn];
int ary[maxn], cnt[maxn];
int Sort(int l, int mid, int r)
{
int ret = 0, pos = l;
int i = l, k = mid + 1;
while(i <= mid && k <= r){
if(ary[i] <= ary[k]){
temp[pos++] = ary[i++];
}else{
temp[pos++] = ary[k++];
ret += mid - i + 1;
}
}
while(i <= mid){
temp[pos++] = ary[i++];
}
while(k <= r){
temp[pos++] = ary[k++];
}
for(i = l; i <= r; i++){
ary[i] = temp[i];
}
return ret;
}
int MergerSort(int l, int r)
{
if(l >= r)
return 0;
int ret = 0;
int mid = (l + r) >> 1;
ret += MergerSort(l, mid);
ret += MergerSort(mid + 1, r);
ret += Sort(l, mid, r);
return ret;
}
int main()
{
while(~scanf("%d", &n) && n){
for(int i = 0; i < n; i++){
scanf("%d", &ary[i]);
cnt[i] = ary[i];
}
int ans = MergerSort(0, n - 1);
int res = ans;
for(int i = 0; i < n; i++){
ans = ans - cnt[i] + n - cnt[i] - 1;
res = res < ans ? res : ans;
}
printf("%d\n", res);
}
return 0;
}
線段樹(78ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 5005;
struct Tree{
int l, r, sum;
};
int n;
int ary[maxn];
Tree tr[maxn << 2];
void Build(int rt, int l, int r)
{
tr[rt].l = l;
tr[rt].r = r;
tr[rt].sum = 0;
if(l == r)
return ;
int mid = (l + r) >> 1;
Build(rt << 1, l, mid);
Build(rt << 1 | 1, mid + 1, r);
}
void Insert(int rt, int pos)
{
tr[rt].sum ++;
if(tr[rt].l == tr[rt].r)
return ;
int mid = (tr[rt].l + tr[rt].r) >> 1;
if(pos <= mid)
Insert(rt << 1, pos);
else
Insert(rt << 1 | 1, pos);
}
int Query(int rt, int l, int r)
{
if(tr[rt].l > r || tr[rt].r < l)
return 0;
if(tr[rt].l >= l && tr[rt].r <= r)
return tr[rt].sum;
return Query(rt << 1, l, r) + Query(rt << 1 | 1, l, r);
}
int main()
{
while(~scanf("%d", &n) && n){
int ans = 0;
Build(1, 0, n - 1);
for(int i = 0; i < n; i++){
scanf("%d", &ary[i]);
Insert(1, ary[i]);
ans += Query(1, ary[i] + 1, n - 1);
}
int res = ans;
for(int i = 0; i < n; i++){
ans = ans - ary[i] + n - ary[i] - 1;
res = res < ans ? res : ans;
}
printf("%d\n", res);
}
return 0;
}
Splay(156ms):
居然只比暴力快一點。。。。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 5005;
struct Tree{
int pre, chd[2];
int val, Size, sum;
void SetTree(int val, int Size, int sum, int pre, int chd0, int chd1){
this->val = val;
this->sum = sum;
this->pre = pre;
this->Size = Size;
this->chd[0] = chd0;
this->chd[1] = chd1;
}
};
int n;
int cut[maxn];
Tree tr[maxn];
int F(int rt){
return tr[tr[rt].pre].chd[1] == rt;
}
void PushUp(int rt)
{
tr[tr[rt].chd[0]].pre = rt;
tr[tr[rt].chd[1]].pre = rt;
tr[rt].Size = tr[tr[rt].chd[0]].Size + tr[tr[rt].chd[1]].Size + 1;
tr[rt].sum = tr[tr[rt].chd[0]].sum + tr[tr[rt].chd[1]].sum + (tr[rt].val != 0);
}
void Rotate(int rt)
{
int chd = F(rt);
int pre = tr[rt].pre;
tr[rt].pre = tr[pre].pre;
tr[tr[pre].pre].chd[F(pre)] = rt;
tr[pre].chd[chd] = tr[rt].chd[!chd];
tr[rt].chd[!chd] = pre;
PushUp(pre);
PushUp(rt);
}
int Splay(int rt, int rw)
{
while(tr[rw].pre != rt){
int pre = tr[rw].pre;
if(F(rw) != F(pre) || tr[pre].pre == rt){
Rotate(rw);
}else{
Rotate(pre);
Rotate(rw);
}
}
if(rt)
PushUp(rt);
return rw;
}
int Insert(int rt, int pos, int val)
{
int ret = rt;
if(tr[tr[rt].chd[0]].Size == pos - 1){
tr[rt].val = val;
}else if(tr[tr[rt].chd[0]].Size >= pos){
ret = Insert(tr[rt].chd[0], pos, val);
}else{
ret = Insert(tr[rt].chd[1], pos - tr[tr[rt].chd[0]].Size - 1, val);
}
PushUp(rt);
return ret;
}
int BuildTree(int Size)
{
for(int i = 1; i < Size; i++){
tr[i].SetTree(0, Size - i + 1, 0, i - 1, 0, i + 1);
}
tr[0].SetTree(0, 0, 0, 0, 0, 0);
tr[Size].SetTree(0, 1, 0, Size - 1, 0, 0);
return 1;
}
int main()
{
int rt;
while(~scanf("%d", &n) && n){
int res = 0;
rt = BuildTree(n + 2);
rt = Splay(0, n + 2);
for(int i = 0; i < n; i++){
scanf("%d", &cut[i]);
int pos = Insert(rt, cut[i] + 2, cut[i] + 2);
rt = Splay(0, pos);
res += tr[tr[rt].chd[1]].sum;
}
int minn = res;
for(int i = 0; i < n; i++){
minn = minn - cut[i] + n - cut[i] - 1;
res = res < minn ? res : minn;
}
printf("%d\n", res);
}
return 0;
}