[2018-2019, ICPC, Asia Yokohama Regional Contest 2018] Problem G-What Goes Up Must Come Down(树状数组)

[2018-2019, ICPC, Asia Yokohama Regional Contest 2018] Problem G-What Goes Up Must Come Down

题面:

Several cards with numbers printed on them are lined up on the table.
We’d like to change their order so that first some are in non-decreasing order of the numbers on
them, and the rest are in non-increasing order. For example, (1, 2, 3, 2, 1), (1, 1, 3, 4, 5, 9, 2),
and (5, 3, 1) are acceptable orders, but (8, 7, 9) and (5, 3, 5, 3) are not.
To put it formally, with n the number of cards and b i the number printed on the card at
the i-th position (1 ≤ i ≤ n) after reordering, there should exist k ∈ {1,...,n} such that
(b i ≤ b i+1 ∀i ∈ {1,...,k − 1}) and (b i ≥ b i+1 ∀i ∈ {k,...,n − 1}) hold.
For reordering, the only operation allowed at a time is to swap the positions of an adjacent card
pair. We want to know the minimum number of swaps required to complete the reorder.

思路:

对于每个数,都有两种选择:

1、参与non-decreasing 部分,成本为:该数之前的比该数大的数的个数。

2、参与non-increasing 部分,成本为:该数之后的比该数大的数的个数。

我们只需要对每一个数的2种选择的成本取一个最小值加起来即可。

然后问题就转化为了对于一个数(a_i),求该数之前的比该数大的数的个数和该数之后的比该数大的数的个数。

方法为:把每一个数的下标都扔进数字对应的桶中,

用树状数组动态处理前缀和,对于([1,n])这n个下标,初始bit里都加1。

然后从小到大枚举数字,建设当前枚举到(mathit x),将x的桶中下标值bit里都减去1,同时用一个变量(residue)代表桶中还剩余多少个数没被删除,设(mathit x) 的下标为(mathit j) 那么:

选择1的成本为:(ask(j))([1,j])的前缀和,因为([1,j])中比(mathit x) 小的数都被之前操作删除过了。

选择2的成本为:(residue-ask(j))([j+1,n])的前缀和。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <unordered_map>
// #include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '
' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '
' : ' ');}}
const int maxn = 1000010;
const ll inf = 1e18;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0

ll tree[maxn];
int lowbit(int x)
{
    return (-x)& x;
}
void add(int pos, int val)
{
    while (pos < maxn)
    {
        tree[pos] += val;
        pos += lowbit(pos);
    }
}
int ask(int pos)
{
    int res = 0;
    while (pos > 0)
    {
        res += tree[pos];
        pos -= lowbit(pos);
    }
    return res;
}
int n;
int a[maxn];
std::vector<int> v[maxn];
int main()
{
#if DEBUG_Switch
    freopen("C:\code\input.txt", "r", stdin);
#endif
    //freopen("C:\code\output.txt","r",stdin);
    n = readint();
    repd(i, 1, n)
    {
        a[i] = readint();
        add(i, 1);
        v[a[i]].push_back(i);
    }
    int residue = n;
    ll ans = 0;
    repd(i, 1, 100000)
    {
        if (sz(v[i]) == 0)
            continue;
        for (auto &x : v[i])
        {
            add(x, -1);
            residue--;
        }
        for (auto &x : v[i])
        {
            ans += min(residue - ask(x), ask(x));
        }
    }
    printf("%lld
", ans );
    return 0;
}
本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
原文地址:https://www.cnblogs.com/qieqiemin/p/13412842.html