Problem:
Score : 800 points

Problem Statement

You are given a string S consisting of lowercase English letters.
Determine whether we can turn S into a palindrome by repeating the operation of swapping two adjacent characters. If it is possible, find the minimum required number of operations.

Constraints

1 \leq |S| \leq 2 × 10^5

S consists of lowercase English letters.

Input

Input is given from Standard Input in the following format:

S

Output

If we cannot turn S into a palindrome, print -1. Otherwise, print the minimum required number of operations.

Sample Input 1

eel

Sample Output 1

1

We can turn S into a palindrome by the following operation:

Swap the 2-nd and 3-rd characters. S is now ele.

Sample Input 2

ataatmma

Sample Output 2

4

We can turn S into a palindrome by the following operation:

Swap the 5-th and 6-th characters. S is now ataamtma.

Swap the 4-th and 5-th characters. S is now atamatma.

Swap the 3-rd and 4-th characters. S is now atmaatma.

Swap the 2-nd and 3-rd characters. S is now amtaatma.

Sample Input 3

snuke

Sample Output 3

-1

We cannot turn S into a palindrome.

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;
using i64 = int64_t;
using vi = vector<i64>;
using vvi = vector<vi>;
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

class SqrtDecomp {
    int B;
    using ii = pair<int, int>;
    vi as;
    vector<deque<i64>> ds;
    vector<unordered_set<i64>> ss;

    inline i64 id(ii a) {
        return i64(2e9) * a.first + a.second;
    }

    i64 shift_begin(int k, int l, const i64 a) {
        i64 ret = ds[k].back();
        ds[k].pop_back();
        ss[k].erase(ret);
        ds[k].insert(ds[k].begin() + l, a);
        ss[k].insert(a);
        return ret;
    }

    i64 shift(int k, const i64 a) {
        ds[k].push_front(a);
        ss[k].insert(a);
        i64 ret = ds[k].back();
        ds[k].pop_back();
        ss[k].erase(ret);
        return ret;
    }

    void shift_end(int k, int r, const i64 a) {
        ss[k].erase(ds[k][r]);
        ds[k].erase(ds[k].begin() + r);
        ss[k].insert(a);
        ds[k].insert(ds[k].begin(), a);
    }

    void shift_begin_end(int k, int l, int r) {
        ds[k].insert(ds[k].begin() + l, ds[k][r]);
        ds[k].erase(ds[k].begin() + r + 1);
    }

public:
    SqrtDecomp(const vi& as) : as(as) {
        for (B = 1; B * B < as.size(); B++);
        ds = vector<deque<i64>>(B);
        ss = vector<unordered_set<i64>>(B);
        for (int i = 0; i < B * B; i++) {
            if (i < as.size()) {
                i64 k = id(ii(i, as[i]));
                ds[i / B].push_back(k);
                ss[i / B].insert(k);
            } else {
                i64 k = id(ii(i, -1));
                ds[i / B].push_back(k);
                ss[i / B].insert(k);
            }
        }
    }

    void rotate(int l, int r) {
        int li = l / B, ri = r / B;
        if (li != ri) {
            i64 s = ds[ri][r % B];
            s = shift_begin(li, l % B, s);
            for (int i = li + 1; i < ri; i++) {
                s = shift(i, s);
            }
            shift_end(ri, r % B, s);
        } else {
            shift_begin_end(li, l % B, r % B);
        }
    }

    int find(int k) {
        i64 t = id(ii(k, as[k]));
        int i;
        for (i = 0; i < B; i++) {
            if (ss[i].count(t)) break;
        }
        for (int j = 0; j < B; j++) {
            if (ds[i][j] == t) {
                return i * B + j;
            }
        }
        assert(0);
    }
};

int main() {
    // assert(freopen("/Users/xuzijian/Downloads/in/03.txt", "r", stdin));
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string s;
    cin >> s;
    queue<i64> que[26];
    int cnt[26] = {};
    vi as;
    for (int i = 0; i < s.size(); i++) {
        as.push_back(s[i]);
    }
    SqrtDecomp sq(as);

    for (int i = 0; i < s.size(); i++) {
        int c = s[i] - 'a';
        cnt[c]++;
        que[c].push(i);
    }

    int ok = 2;
    for (int i = 0; i < 26; i++) {
        if (cnt[i] % 2) {
            ok--;
        }
    }
    if (ok <= 0) {
        cout << -1 << endl;
        return 0;
    }

    int need[26] = {};
    for (int i = 0; i < 26; i++) {
        need[i] = cnt[i] / 2;
    }

    i64 ans = 0;
    int id = 0;
    vi pal(s.size());
    unordered_set<int> alpha;
    for (int i = 0; i < 26; i++) {
        if (need[i]) {
            alpha.insert(i);
        }
    }
    while (1) {
        if (id == s.size()) break;
        if (id < s.size() / 2) {
            int nin = 1e9, ch;
            for (int i: alpha) {
                int t = que[i].front();
                // int k = sq.find(t);
                if (t < nin) {
                    nin = t;
                    ch = i;
                }
            }
            nin = sq.find(nin);
            ans += nin - id;
            need[ch]--;
            if (need[ch] == 0) {
                alpha.erase(ch);
            }
            que[ch].pop();
            pal[id] = ch;
            if (id != nin) {
                sq.rotate(id, nin);
            }
            id++;
        } else if (s.size() % 2 && id == s.size() / 2) {
            for (int i = 0; i < 26; i++) {
                if (cnt[i] % 2) {
                    int t = que[i].front();
                    int k = sq.find(t);
                    ans += k - id;
                    que[i].pop();
                    // pal += 'a' + i;
                    if (k - id != 0) {
                        sq.rotate(id, k);
                    }
                    id++;
                    break;
                }
            }
        } else {
            int r = s.size() - 1 - id;
            int c = pal[r];
            // assert(que[c].size());
            int t = que[c].front();
            int k = sq.find(t);
            ans += k - id;
            que[c].pop();
            // pal += 'a' + c;
            if (k - id != 0) {
                sq.rotate(id, k);
            }
            id++;
        }
    }

    // cout << pal << endl;
    cout << ans << endl;
}