Submission #551321

#TimeUsernameProblemLanguageResultExecution timeMemory
551321apostoldaniel854Diversity (CEOI21_diversity)C++14
64 / 100
7089 ms16412 KiB
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
#define dbg(x) cerr << #x << " " << x << "\n"

const int MAX_N = 3e5;
int n, Q;
int a[1 + MAX_N];

ll solve(vector <int> &v) {
    int sz = v.size ();
    ll ans = 0;
    for (int l = 0; l < sz; l++) {
        map <int, int> freq;
        for (int r = l; r < sz; r++) {
            freq[v[r]]++;
            ans += freq.size();
        }
    }
    return ans;
}

ll brute_force() {
    vector <int> order(n);
    for (int i = 0; i < n; i++)
        order[i] = i + 1;
    ll ans = (1ll << 60);
    vector <int> best;
    do {
        vector <int> v;
        for (int i : order)
            v.push_back(a[i]);
        ll cnt = solve(v);
        if (ans > cnt) {
            best = v;
            ans = cnt;
        }
    } while (next_permutation(order.begin(), order.end()));
    cout << ans << "\n";
    for (int x : best)
        cout << x << " ";
    cout << "\n";
    return ans;
}

/// maybe we need to add the one with lowest freq closer to the edges
/// can we do this greedy or just by dp? greedy works!

int freq[1 + MAX_N];

ll get_div(int l, int r, int sz) {
    ll ans = 0;
    /// out out
    ans += 1ll * (l - 1) * (sz - r);
    /// in out
    ans += 1ll * (r - l + 1) * (sz - r);
    /// out in
    ans += 1ll * (r - l + 1) * (l - 1);
    /// in in
    ans += 1ll * (r - l + 1) * (r - l + 2) / 2;
 //   dbg (ans);
    return ans;
}

ll greedy_v1() {
    for (int i = 1; i <= n; i++)
        freq[a[i]]++;
    vector <int> values;
    for (int i = 1; i <= MAX_N; i++)
        if (freq[i])
            values.push_back(freq[i]);
    sort (values.begin(), values.end());
    int l = 1, r = n;
    int putL = 0, putR = 0;
    ll ans = 0;
    for (int cnt : values) {
        if (putL < putR) {
            putL += cnt;
            ans += get_div(l, l + cnt - 1, n);
            l += cnt;
        }
        else {
            putR += cnt;
            ans += get_div(r - cnt + 1, r, n);
            r -= cnt;
        }
    }
    return ans;
}

const int RADMAX = 500;

struct Query {
  int st;
  int dr;
  int ind;
};

vector <Query> q[RADMAX];

ll sol[1 + MAX_N];
int car[1 + MAX_N];
bool cmp (Query a, Query b) {
  return a.dr < b.dr;
}

int rad;

inline int bucket (int x) {
  return x / rad;
}
multiset <int> st;
void upd(int value, int val) {
    if (car[value])
        st.erase(st.find(car[value]));
    car[value] += val;
    if (car[value])
        st.insert(car[value]);
}
ll get(int L, int R){
    int putL = 0, putR = 0;
    ll ans = 0;
    int l = 1, r = R - L + 1;
    for (int cnt : st) {
        if (putL < putR) {
            putL += cnt;
            ans += get_div(l, l + cnt - 1, R - L + 1);
            l += cnt;
        }
        else {
            putR += cnt;
            ans += get_div(r - cnt + 1, r, R - L + 1);
            r -= cnt;
        }
    }
    return ans;
}
void query_mode() {
    rad = sqrt(n);
    for (int i = 1; i <= Q; i++) {
        int x, y;
        cin >> x >> y;
        q[bucket (x)].push_back ({x, y, i});
    }
    for (int b = 0; b <= rad; b++) {
        sort (q[b].begin (), q[b].end (), cmp);
        memset (car, 0, sizeof (car));
        st.clear();
        int dr = (b + 1) * rad;
        for (auto w : q[b]) {
          while (dr <= w.dr) {
            upd(a[dr], 1);
            dr++;
          }
          int bound = min (w.dr, (b + 1) * rad - 1);
          for (int i = w.st; i <= bound; i++)
            upd(a[i], 1);
          sol[w.ind] = get(w.st, w.dr);
          for (int i = w.st; i <= bound; i++)
            upd(a[i], -1);
        }
    }
    for (int i = 1; i <= Q; i++)
        cout << sol[i] << "\n";
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> Q;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    query_mode();
    /*
    while (q--) {
        int l, r;
        cin >> l >> r;
    }
    ll ans_brute = brute_force();
    ll ans_greddy = greedy_v1();
    cout << ans_brute << " " << ans_greddy << "\n";*/
    return 0;
}
/**
4 2
1 1 1 1
1 2
2 4

**/
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...