1332 字
7 分钟
Fair Distribution
问题理解与转化
1.题目概述
- 有 n 个机器人 和 m 个能量棒,现在你能进行两个操作
- 1.消灭一个机器人
- 2.产生一个能量棒
- 要求操作后的 m1 % n1 == 0 的最小操作数
输入:
33 1210 68 20输出:
042关键约束: 数据量大,不支持一个个算,需要有一些快速的办法计算
问题理解: 题目问我们的是能分配的前提下,最小的操作数
- 操作数:
- 能够分配:
- 根据这两个式子带入约化得到只包含 的函数表达式,故可以计算答案
2. 核心思路阐述
解题思路
- 根据式子式子代入,我们会得到一个式子:
- 关键转换 ->
- 根据式子我们可以清晰发现,题目转换为取 使得函数 最小
关键观察
- 观察式子发现 这是经典的数论分块(整除分块)形式
- 每当取一个
n都会有一个区间[l,r]使得 的相同,因为的值是固定的,因此要使取到最小值,必须尽量让取小, 让即可
3. 详细算法设计
- 步骤分解:
- 根据上面分析,我们只需要遍历所有 所有可能的值,并将 代入即可
- 计算
[l,r]:l从1开始,r取带入l与相等的最大值 - 设
- 用
l带入式子得到答案,取min,l = r + 1开始遍历查找.
for(int l = 1, r; l <= n; l = r + 1){ int v = x / l; //这里的 l 和 r 表示 选择[l, r]区间的任何数 floor((m-1)/i) 都相等 r = (v == 0) ? n : min(n, x / v); //数论分块理论 ans = min(ans, n - m + l * (x / l)); }- 复杂度分析
- 每一个问题需要的时间计算
4. 正确性证明
-
边界情况:选择全增加能量棒
-
特殊情况:当时,由于n只能减少,m只能增加,故最小的操作数就是
-
数学证明: 设 ,其中 , 为整数。
-
若 ( 被 整除):
左边 ;
右边 。 -
若 :
左边 ;
右边
(因为 ,故 )。
验证逻辑的正确性
- 我们证明了公式的正确性,满足和
m能被n整除的两个条件 - 我们遍历了所有可能存在的值,并取最小的,对答案取min
- 特判
n > m 和 全部用来制作能量棒的特殊情况 - 最后得到的答案一定是所有答案中最小的一个
5. 复杂度分析
-
时间复杂度:计算单个答案
-
空间复杂度:(忽略)
-
实际性能:
6. 代码实现
#include <bits/stdc++.h>
using namespace std;#define int long long#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)#define x first#define y second#define endl "\n"typedef signed long long LL;typedef pair<int, int> PII;
const int N = 1e5 + 10;//f(n`) = (n - n`) + (m` - m)// 注意:这里的公式推导// 原式 = (n-i) + (ceil(m/i)*i - m)// = n - m + i * (ceil(m/i) - 1)// = n - m + i * floor((m-1)/i)// 所以代价是 ans = min(ans, n - m + l * v);void solve() { int n, m; cin >> n >> m; if(n > m) { cout << n - m << endl; return; } int x = m - 1; int ans = (n - m % n) % n; //全部都添加 能量棒 for(int l = 1, r; l <= n; l = r + 1){ int v = x / l; //这里的 l 和 r 表示 选择[l, r]区间的任何数 floor((m-1)/i) 都相等 r = (v == 0) ? n : min(n, x / v); //数论分块理论 ans = min(ans, n - m + l * (x / l)); } cout << ans << endl;}
signed main(){ IOS; int _ = 1; cin >> _; while(_--){ solve(); }}7. 常见错误与陷阱
-
易错点分析:数学公式计算容易出错,要对**数论分块(整除分块)**有一定理解
-
调试技巧:公式的验证
8. 拓展与变种
-
相关问题:暂无
-
实际应用:计算数学整除的一些问题
9. 总结与收获
总结:
- 一个数论题,需要有一定的数学知识,将现有公式转化成我们所想要的表达式,根据表达式的特性,取决我们的操作
核心知识点
- 数论分块(整除分块)
思维模式
- 先读题,按照题目意思列出式子
- 将式子整合在一起,约化成简单的式子
- 看能否通过现有式子,转换成枚举求 最大 / 最小 的问题
- 用公式转换问题
学习建议
- 数学的问题一般要有很多前置知识,若是不会,则很难能在比赛中写出来,需要多多训练,巩固这些知识
Fair Distribution
https://blog.rookiesama.space/posts/题解/fair-distribution/ 部分信息可能已经过时









