[数论]中南大学 2013 校赛 G 题解题报告
2013-04-14 23:58
232 查看
Balls
and Boxes
N 个盒子,原本有一些球;每次可以向 M 个不同的盒子里面各放一个球,问最少要多少次操作能让盒子里面的球数量相等。不可以输出 -1.
方法是——记录所有盒子的最大值 Max , 和 Sum , 最小值 Min。
那么如果最后能够达成,高度为H , 那么肯定满足以下三个条件
1、H >= Max
2、(n * H - Sum) % m == 0
3、要做的操作数T = (n * H - Sum) / m , 那么 T >= H - Min【重要!!!】
那么要做的事情就是首先解第二个方程,可以将他转化成最简单的 ax = b (mod n) 形式——
(n * H) = (m - Sum % m) % m (mod m)
解这个方程,首先假设 A * x + B * m = C ,用 extendGCD 求出来一组解和C 。 那么如果 (m - Sum % m) % C != 0 (或者是 Sum mod GCD(n , m) != 0) 的话一定没解。。
其次,再讲问题转化一下,我们求出来最小的 Hmin , 那么 H 的解就可以转化成 H + i * m / C ....巧合的是,我们之前用 extendGCD 已经求出来了一个 n 但是 n 可能是负数。
那么就每次加上 m / C 一直到 n >= Max 为止。
但是这就是答案了么?明显不是,看下面这组数据
3
0 100000 100000
明显答案是 200000 , 不是 50000 。 那怎么办呢?就要用到第 3 个性质
方法是 二分。假设答案是 Hmin + ans * m / C . 那么枚举上下界二分即可,要求满足的是 T >= H + i * m / C
and Boxes
题意
N 个盒子,原本有一些球;每次可以向 M 个不同的盒子里面各放一个球,问最少要多少次操作能让盒子里面的球数量相等。不可以输出 -1.
解法:
一开始写了一个姿势 wa了,换了一个姿势就过了方法是——记录所有盒子的最大值 Max , 和 Sum , 最小值 Min。
那么如果最后能够达成,高度为H , 那么肯定满足以下三个条件
1、H >= Max
2、(n * H - Sum) % m == 0
3、要做的操作数T = (n * H - Sum) / m , 那么 T >= H - Min【重要!!!】
那么要做的事情就是首先解第二个方程,可以将他转化成最简单的 ax = b (mod n) 形式——
(n * H) = (m - Sum % m) % m (mod m)
解这个方程,首先假设 A * x + B * m = C ,用 extendGCD 求出来一组解和C 。 那么如果 (m - Sum % m) % C != 0 (或者是 Sum mod GCD(n , m) != 0) 的话一定没解。。
其次,再讲问题转化一下,我们求出来最小的 Hmin , 那么 H 的解就可以转化成 H + i * m / C ....巧合的是,我们之前用 extendGCD 已经求出来了一个 n 但是 n 可能是负数。
那么就每次加上 m / C 一直到 n >= Max 为止。
但是这就是答案了么?明显不是,看下面这组数据
3
0 100000 100000
明显答案是 200000 , 不是 50000 。 那怎么办呢?就要用到第 3 个性质
方法是 二分。假设答案是 Hmin + ans * m / C . 那么枚举上下界二分即可,要求满足的是 T >= H + i * m / C
代码
LL n , m; LL a[20000]; void solve(){ RD(n , m); LL s = 0 , h = 0 , l = 1e9; REP(i , n) { RD(a[i]); checkMax(h , a[i]); checkMin(l , a[i]); s += a[i]; } LL d = GCD(n , m); if (s % d != 0){ puts("-1"); return; } LL x , y; d = extendGCD(n , m , x , y); x *= s / d; LL inc = m / d; LL ins = (h - x) / inc; x += ins * inc; if (x < h) x += inc; // cout << inc << endl; LL low = 0 , high = 1e9 , mid , ans = 1e9; do{ mid = low + high >> 1; LL xx = x + inc * mid; LL t = (xx * n - s) / m; if (xx - l <= t){ checkMin(ans , mid); high = mid - 1; } else low = mid + 1; }while(low <= high); printf("%lld\n" , ((x + inc * ans) * n - s) / m); } int main(){ // freopen("0.txt" , "r" , stdin); Rush solve(); }
相关文章推荐
- ZOJ Monthly, March 2013 解题报告
- hdoj-2013-蟠桃记(解题报告)
- Luogu1983 [NOIP2013]车站分级 解题报告【图论】【拓扑排序】【栈】
- 2013 ACM/ICPC 长沙网络赛B题解题报告
- haoi2013软件安装解题报告
- 第三届华中区程序设计邀请赛暨武汉大学第十二届校赛 网络预选赛 水题解题报告
- 【扩散】【福利】NOIp2013提高组解题报告
- SHU 2013 暑期集训(7-15)解题报告
- HDU 4578 Transformation 解题报告(线段树,2013杭州邀请赛)
- FOJ 2013 A short problem 解题报告
- 第二届华中区程序设计邀请赛暨武汉大学第十一届校赛 网络预选赛 解题报告
- 中南大学2012暑期集训中期检测训练赛“跳跳”解题报告
- 2013NBUT暑期集训成果赛 赛后总结以及解题报告
- Facebook Hacker Cup 2013 Qualification Round 解题报告
- FOJFOJ有奖月赛-2012年4月(校赛热身赛)-解题报告总结
- 2013 Multi-University Training Contest 6 解题报告(更新中)
- 2014哈商大ICPC/ACM校赛解题报告
- BZOJ 2118 数论+最短路(SPFA) 解题报告
- 【图论基础练习】 SCU 2013 Summer Traing 3 - Graph Theory (1) 解题报告
- NOIP2013提高组Day1 解题报告