Submission #1305042

#TimeUsernameProblemLanguageResultExecution timeMemory
1305042OgradLBoarding Passes (BOI22_passes)C++20
100 / 100
308 ms183368 KiB
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;

void bucket_sort(int M, vector<int>& arr, function<int(int)> cmp){
	vector<vector<int>> buckets(M);

	for (int x : arr){
		buckets[cmp(x)].push_back(x);
	}

	int idx = 0;
	for (int i = 0; i < M; i++){
		for (int x : buckets[i]){
			arr[idx++] = x;
		}
	}
}

const int G = 15;
vector<vector<int>> pos;
vector<vector<vector<int>>> prefs;
vector<vector<vector<int>>> suffs;

long long calc(long long front, int i, int m){
	int split = 0;

	if (front < pos[i].size())
		split = pos[i][front];
	else
		split = pos[i][front-1]+1;

	long long back = (int)pos[i].size() - front;

	long long ans = 0;
	for (int b = 0; b < G; b++){
		if (b == i)
			continue;
		if ((m & (1 << b)) == 0)
			continue;
		ans += prefs[i][b][split] + suffs[i][b][split];
	}
	ans *= 2;
	ans += front * (front - 1) / 2;
	ans += back * (back - 1) / 2;
	return ans;
};

long long cost(int i, int m){
	if (pos[i].size() == 0)
		return 0;

	int lo = 0, hi = pos[i].size(), mid;
	while (lo + 1 < hi){
		mid = (lo + hi) / 2;

		if (calc(mid, i, m) > calc(mid+1, i, m)){
			lo = mid+1;
		} else {
			hi = mid;
		}
	}

	long long res = min(calc(lo, i, m), calc(hi, i, m));

	return res;
};

int main(){

	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	string S;
	cin >> S;

	int N = S.size();

	pos.assign(G, vector<int>());
	prefs.assign(G, vector<vector<int>>(G, vector<int>(N+1, 0)));
	suffs.assign(G, vector<vector<int>>(G, vector<int>(N+1, 0)));

	for (int i = 0; i < N; i++){
		pos[S[i] - 'A'].push_back(i);
	}

	for (int i = 0; i < G; i++){
		for (int j = 0; j < G; j++){
			if (j == i)
				continue;
			int cnt_j = 0;
			prefs[i][j][0] = 0;
			for (int i0 = 0; i0 < N; i0++){
				long long c = 0;
				if (S[i0] == 'A' + j){
					cnt_j++;
				}
				if (S[i0] == 'A' + i){
					c = cnt_j;
				}
				prefs[i][j][i0+1] = prefs[i][j][i0] + c;
			}

			cnt_j = 0;
			suffs[i][j][N] = 0;
			for (int i0 = N-1; i0 >= 0; i0--){
				long long c = 0;
				if (S[i0] == 'A' + j){
					cnt_j++;
				}
				if (S[i0] == 'A' + i){
					c = cnt_j;
				}
				suffs[i][j][i0] = suffs[i][j][i0+1] + c;
			}
		}
	}


	vector<int> masks(1 << G);
	iota(masks.begin(), masks.end(), 0);

	bucket_sort(G+1, masks, [](int mask){
		return __builtin_popcount(mask);
	});

	vector<long long> dp(1 << G, 1e18);
	dp[0] = 0;

	for (int mask : masks){
		for (int i = 0; i < G; i++){
			if (mask & (1 << i))
				continue;

			long long c = cost(i, mask);

			dp[mask | (1 << i)] = min(dp[mask | (1 << i)], dp[mask] + c);
		}
	}

	long long ans = dp[(1 << G) - 1];
	cout << ans / 2 << ((ans & 1) ? ".5" : "") << "\n";
	
	return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...