《补题》(牛客:Tokitsukaze and K-Sequence)

87 阅读1分钟

思维

x表示当前数的个数,k表示当前区间个数
f(x,k)
if(x > k) f(x,k) = k - 1
else f(x,k) = x
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 998244353;
const int N = 100010;
int a[N], cnt[N];
multiset<int> tmp;	
void solve() {
	int n;
	cin >> n;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 0; i < n; i ++) {
		cin >> a[i];
		cnt[a[i]] ++;//统计每个数出现的次数
	}
	for (int i = 0; i < N; i ++) {
		if (cnt[i]) {
			tmp.insert(cnt[i]);//把每个数出现的次数插入到multiset中
		}
	}
	ll sum = 0, len = tmp.size();//sum记录贡献和,len记录当前数的个数超过区间的数的总个数 
	for (int i = 1; i <= n; i ++) {//i模拟区间个数 
		while (!tmp.empty() && *tmp.begin() <= i) {
			sum += *tmp.begin();
			tmp.erase(tmp.begin());//删除当前第一个元素
			len --;
		}
		cout << sum + (i - 1) * len << endl;
	}//如果当前数的个数不超过区间的数的总个数 贡献和 += 当前数的个数
}//否则 贡献和 += 区间数 - 1
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int _ = 1;
	int t;
	cin >> t;
	while (t --) {
		solve();
	}
	return 0;
}