1. 程式人生 > 其它 >CF EDU 112 D - Martial Arts Tournament

CF EDU 112 D - Martial Arts Tournament

D - Martial Arts Tournament

列舉

不能列舉 x, y ,但是可以列舉集合大小,設三個集合大小分別為 \(2^i,2^j,2^k\), 列舉 i,j 即可,複雜度為 \(O(nlognlogn)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;

const int N = 2e5 + 10;
int n;
int mp[N];

int solve(int w1, int w2)
{
	int res = 0, sum = 0, i = 1;
	//第一個集合要加多少
	for ( ; i <= n; i++)
	{
		if (sum + mp[i] > w1)
			break;
		sum += mp[i];
	}
	res += w1 - sum;
	//第二個集合要加多少
	sum = 0;
	for ( ; i <= n; i++)
	{
		if (sum + mp[i] > w2)
			break;
		sum += mp[i];
	}
	res += w2 - sum;
	
	int w3 = 1;
	sum = 0;
	for ( ; i <= n; i++)
		sum += mp[i];
	//原來 n 個數中還剩 sum 個,第三個集合大小應是 >= sum 的 2 的冪
	while(w3 < sum)
		w3 <<= 1;
	res += w3 - sum;
	return res;
}
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n;
		fill(mp, mp + n + 2, 0);
		for (int i = 1; i <= n; i++)
		{
			int x;
			cin >> x;
			mp[x]++;
		}
		int ans = 1e9;
		for (int i = 0; (1 << i) <= n; i++)
			for (int j = 0; (1 << j) <= n; j++)
				ans = min(ans, solve(1 << i, 1 << j));
		cout << ans << endl;
	}
	return 0;
}