3 条题解

  • 1
    @ 2024-6-29 19:57:33

    S001B. 催化剂

    Statement\mathsf{\color{Thistle}Statement}

    给定一个长度为 nn 的序列 aaii 位置表示有一个种类为 aia_i 的糖果(aia_i 可以重复,即同一个种类有多个糖果),接下来有 qq 次查询:

    • 1 x:表示种类 xx 多了 11 个糖果
    • 2 x:表示种类 xx 少了 11 个糖果
    • 3 k:输出将所有糖果分给 kk 个小朋友的最小愤怒值之和
      • 愤怒值:令第 ii 个小朋友所拥有的第 jj 种糖果的数量为 bi,jb_{i,j},则愤怒值之和为 i=1kj=1nmax(0,bi,j1)\sum_{i=1}^k \sum_{j=1}^n \max(0,b_{i,j}-1)

    Solution\mathsf{\color{Thistle}Solution}

    若第 ii 种糖果的数量为 cic_i,则对于 kk 个小朋友,最小愤怒值为 i=1nmax(0,cik)\sum_{i=1}^n \max(0,c_i-k),其实就是每种糖果平均分给 kk 个小朋友,可以证明这是最优的。比如说:糖果为 2,2,2,2,3,5,52,2,2,2,3,5,522 个小朋友,划分方案如下。

    第一个小朋友 第二个小朋友
    2,2,3,5,52,2,3,5,5 2,2,52,2,5

    那么,问题转化为了动态求出现所有出现次数 k\ge k 的数的和 - k×k\times 出现次数 k\ge k 的数的个数。这个是可以通过平衡树来维护的,不过难写且麻烦。

    不妨考虑将询问离线,对于一次更改,相当于对所有 cnt\le cnt 询问作统一的更改(cntcnt 表示当前更改后该糖果种类的数量)。故,考虑将询问排序,每次更改通过树状数组实现即可。

    Code\mathsf{\color{Thistle}Code}

    signed main() {
    	cin.tie(0);
    	cout.tie(0);
    	ios::sync_with_stdio(0);
    
    	cin >> n >> q;
    	int op, x;
    	for (int i = 1; i <= n; i ++)
    		cin >> x, opr[ ++ m] = {x, 1};
    	while (q -- ) {
    		cin >> op >> x;
    		if (op == 1) opr[ ++ m] = {x, 1};
    		else if (op == 2) opr[ ++ m] = {x, -1};
    		else k ++, qry[k] = {x, k}, upd[m].push_back(k);
    	}
    	sort(qry + 1, qry + 1 + k);
    	for (int i = 1; i <= k; i ++) pos[qry[i].se] = i;
    
    	for (int i = 1; i <= m; i ++) {
    		sum.add(lst[opr[i].fi], -tot[opr[i].fi]);
    		tot[opr[i].fi] += opr[i].se;
    		cnt.add(lst[opr[i].fi], -1);
    		int l = 1, r = k, ans = -1;
    		while (l <= r) {
    			int mid = l + r >> 1;
    			if (qry[mid].fi < tot[opr[i].fi]) l = mid + 1, ans = mid;
    			else r = mid - 1;
    		}
    		if (ans == -1) lst[opr[i].fi] = 0;
    		else lst[opr[i].fi] = k - ans + 1, sum.add(lst[opr[i].fi], tot[opr[i].fi]), cnt.add(lst[opr[i].fi], 1);
    		for (auto v : upd[i])
    			res[v] = sum.sum(k - pos[v] + 1) - qry[pos[v]].fi * cnt.sum(k - pos[v] + 1);
    	}
    
    	for (int i = 1; i <= k; i ++)
    		cout << res[i] << endl;
    
    	return 0;
    }
    

    信息

    ID
    3
    时间
    1000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    465
    已通过
    95
    上传者