首页 > 其他分享 >CF999D Equalize the Remainders 题解

CF999D Equalize the Remainders 题解

时间:2024-03-18 15:03:41浏览次数:24  
标签:CF999D nxt set frac Remainders int 题解 pos 模数

题意

给定一个长度为 \(n\) 的序列和一个模数 \(m\),记 \(c_i\) 表示 \(\bmod m\) 后的结果为 \(i\) 的数的个数。现在可以使每个数增加 \(1\),请问最少要操作多少次才能使所有 \(c_i = \frac{n}{m}\)。并输出最后的序列。

First. 如何最小化操作次数

由于每次操作会使 \(c_{a_i \bmod m} - 1\),\(c_{(a_i + 1) \bmod m} + 1\),那么不妨先将所有 \(a_i\) 按照 \(\bmod m\) 后的结果分组,下文称模数集合。对于每个余数考虑是否将其中的一些数给到下一个没有达到 \(\frac{n}{m}\) 的余数。

对于 \(c_i > \frac{n}{m}\) 的模数 \(i\),首先,它里面的值一定都要加至没要达到 \(\frac{n}{m}\) 的模数集合里。那么,肯定移动到的模数集合的距离越近越好。所以,可以用一个 set 来维护所有没有达到 \(\frac{n}{m}\) 的模数,查找离其最近的一个模数 \(nxt\),然后将 \(i\) 中的元素加至 \(nxt\) 中。

这里的查找可以用 s.lower_bound。如果没有,那么取 set 里的第一个元素(因为模数 \(+ 1\) 是循环的)。

每次操作完,如果该模数已经满足,那么将其从 set 中删去。

这样,由于每次我们移动都是移至最近的一个没有满足的模数(移至满足了的模数没有意义,因为枚举到它的时候又会传给下一个数),那么操作次数也肯定是最少的。

Second. 怎么输出序列

这个很简单,你在维护集合的过程中,集合中既存数值,也存该数值的编号。移动的时候只修改值。最后再加上修改完的值与原来的值的差即可。

Third. 细节和时间复杂度分析

时间复杂度分析

对于每个数,我们只将其分组 + 移动,移动过后不会再操作(因为刚好达到条件的组不需要再次操作),而每次移动是 \(O(\log_2n)\) 的,数又有 \(n\) 个,于是整体复杂度是 \(O(n \log_2n)\) 的。

细节

  1. 题目要求最终的值不能超过 \(10^{18}\) 那么每次移动数要尽可能小。

Code

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N = 2e5 + 10;
int n, m;
int a[N], c[N];
set<int> s;
vector< pair<int, int> > b[N];

signed main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	int len = n / m;
	for (int i = 1; i <= n; i ++) cin >> a[i], b[a[i] % m].push_back({a[i], i});
	for (int i = 0; i < m; i ++) {
		sort(b[i].begin(), b[i].end(), greater<pair<int, int> > ());
		if (b[i].size() < len) s.insert(i);
	}
	for (int i = 0; i < m; i ++) {
		while (b[i].size() > len) {
			auto pos = s.lower_bound(i);
			pair<int, int> ft = b[i].back();
			b[i].pop_back();
			if (pos == s.end()) pos = s.begin();
			int nxt = *pos;
			b[nxt].push_back({ft.first + (nxt - i + m)% m/*操作次数*/ , ft.second});
			if (b[nxt].size() == len) s.erase(pos);
		}
	}
	for (int i = 0; i < m; i ++) {
		for (auto x : b[i]) {
			c[x.second] = x.first;
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i ++) {
		ans += c[i] - a[i];
	}
	cout << ans << endl;
	for (int i = 1; i <= n; i ++) cout << c[i] << ' ';
	return 0;
}

标签:CF999D,nxt,set,frac,Remainders,int,题解,pos,模数
From: https://www.cnblogs.com/Ice-lift/p/18080405

相关文章

  • AT_hhkb2020_e Lamps 题解
    \(\mathtt{TAG}\):计数、数学变量说明下文中\(k\)指整洁方块个数。First.如何计数?一个方案一个方案地数肯定是不现实的,不妨反过来想:每个方块在多少个方案中被照亮。Second.如何求多少个方案首先预处理出有多少位置可以将\(s_{i,j}\)照亮。记为\(x\)。这个很简单,不......
  • CF933-Div3 大致思路+题解
    A-RudolfandtheTicket纯水题暴力枚举直接过$code$#include<bits/stdc++.h>#definefo(x,y,z)for(int(x)=(y);(x)<=(z);(x)++)#definefu(x,y,z)for(int(x)=(y);(x)>=(z);(x)--)inlineintqr(){ charch=getchar();intx=0,f=1; for(;ch<'0......
  • 【题解】A18535.来自领导的烦恼
    题目跳转思路:本题可以使用动态规划或递归的方式来实现,本质上是一道01背包的变型题。假设一共有\(n\)名员工,每一位员工的技能水平用\(a[i]\)表示。要使得两个部门的员工技能总和之差最小,意思就是尽可能地将一个部门的技能之和”凑“到\(\sum\limits_{i=1}^{n}a[i]\times\frac{1}......
  • 【题解】A18536.星光交错的律动
    题目跳转思路:这道题可能跟博弈论有一点关系,没有学习过博弈论做起来应该问题也不大。思考一个问题,先手必胜的前提是什么?有关更多的内容可以前往:浅谈有向无环图先手必胜的前提是,在任何一种局面下,先手都有至少一种操作可以使后手处于必败的局面。若先手进行任何操作后,后手都可以......
  • 【题解】A18537.我心中珍藏的游戏
    题目跳转思路:题目问最多可以获得的额外伤害,其实就是询问在这些技能中,如何怎样选取一个最优的发动技能顺序使得攻击加成最大。我们可以把每一个技能看作成一个图的顶点,把每一个攻击加成看作图的边,权制为\(Ei,j\)。由于\(Ei,j\)与\(Ej,i\)相等,则可以将这个图视为无向图。可以样样......
  • 【题解】P2627 [USACO11OPEN] Mowing the Lawn G
    【题解】P2627[USACO11OPEN]MowingtheLawnG题目跳转数据量比较大,暴力肯定是不行的。只能考虑用动态规划的方式来做。这道题有许多dp设计的思路,这里提供两个:方法一:普通状态设计定义\(dp[i][1/0]\)表示截止遍历到第\(i\)个元素时,选择第\(i\)个元素或不选第\(i\)个元素可以......
  • cfRound933div3-E题解
    E-RudolfandkBridges题意:选择的桥在连续的行中,每个桥的支架安装位置是可以不一样的.做法:赛时也感觉也感觉是dp,但是害怕dp,就选择了逃避.往贪心方向想,认为每次到了每个跳板都要跳到最远距离,实际上这样是不行的.很明显,可能存在近一点的点花费更少。实际上是dp,而且也不......
  • [ABC258F] Main Street 题解
    题意:你要在平面直角坐标系中行走,每一步可以上下左右四个方向任意移动$1$,耗时$k$秒。特别地,存在若干条快速通道,若该步起点和终点均满足$x\equiv0\pmod{B}$或$y\equiv0\pmod{B}$,则认为该步是在快速通道上进行,仅需耗时$1$秒。询问从$(S_x,S_y)$到$(G_x,G_y)$最......
  • P3939 数颜色 题解
    题目链接:数颜色经典题目了,暴力数据结构随便过,不过这种不带修的单个颜色的数量查找有个经典的做法:分桶+二分。具体的为每个颜色分桶,记录有序下标,这样就可以二分出\([l,r]\)上的下标个数。对于一次交换来说,如果相邻的颜色相同那么并不会发生交换,如果不同那么就发生交换,由于下标在......
  • P10218 [省选联考 2024] 魔法手杖 题解
    Description给定\(a_1,a_2,\dots,a_n\)以及\(b_1,b_2,\dots,b_n\),满足\(a_i\in[0,2^k-1]\)以及\(b_i\geq0\),你需要给出\(S\subseteq\{1,2,\dots,n\}\)以及\(x\in[0,2^k-1]\)满足以下条件:\(\sum\limits_{i\inS}b_i\leqm\);满足以上条件的前提下,最大化\......