要求O(1)解决

100面值(c张),50面值(b张),10面值(a张),可乐单价×
原则(1):用户先用大面值,然后可乐售卖机找零。
原则(2):机器内找零的张数是无限的,优先找零大面值,不足大面值再用小面值的找零。
问题:假设买的可乐数量M瓶,用户要投钱几次?
要求O(1)解决




- 我尽可能地去看100元面值(只能花100面值)的能帮我搞定多少瓶,(a瓶)
- 我尽可能地去看50元面值(可以花100面值,50面值,但不能花10面值的)的能帮我搞定多少瓶,(b瓶)
。。。。。
只要任一时刻达到了m瓶,我就停,就求出了最小投币数
麻烦的是啥? 之前的面值会留下小尾巴

为什么当面面值买的第一瓶可乐如此特殊?
因为它有可能把它之前的小尾巴全部清掉

- 除法向上取整怎么搞最快?

public static int putTimes(int m, int a, int b, int c, int x) {int[] qian = {100, 50, 10};int[] zhang = {c, b, a};//总共需要多少次投币int puts = 0;// 之前面值的钱还剩下多少总钱int preqianRest = 0;// 之前面值的钱还剩下多少总张数int preqianZhang = 0;for (int i = 0; i < 3 && m != 0; i++) {// 要用之前剩下的钱和当前面值的钱,共同买第一瓶可乐// 之所以之前的面值会剩下来,一定是剩下的钱,一直攒不出一瓶可乐的单价// 当前的面值付出一些钱 + 之前剩下的钱,此时有可能凑出一瓶可乐来// 那么当前面值参与搞定第一瓶可乐,需要掏出多少张呢? 就是curQianFirstBuyZhangint curQianFirstBuyZhang = (x - preqianRest + qian[i] - 1) / qian[i]; // 向上取整的快速方式if (zhang[i] >= curQianFirstBuyZhang) { // 如果之前的钱和当前面值的钱,能凑出第一瓶可乐// 凑出来了一瓶可乐也可能存在找钱的情况giveRest(qian, zhang, i + 1, (preqianRest + qian[i] * curQianFirstBuyZhang) - x, 1);puts += curQianFirstBuyZhang + preqianZhang;zhang[i] -= curQianFirstBuyZhang;m--;} else { // 之前的钱和当前面值的钱不能凑出第一瓶可乐preqianRest += qian[i] * zhang[i];preqianZhang += zhang[i];continue;}// 凑出第一瓶可乐,把之前的小尾巴清掉之后,当前面值有可能继续买更多的可乐,// 以下过程就是后续的可乐怎么用当前面值的钱来买// 用当前面值的钱买一瓶可乐需要多少张int curQianBuyOneColaZhang = (x + qian[i] - 1) / qian[i]; // 向上取整的快速方式// 用当前面值的钱,一共可以搞定几瓶可乐int curQianBuyColas = Math.min(zhang[i] / curQianBuyOneColaZhang, m);// 用当前面值的钱,每搞定一瓶可乐,售货机会吐出多少零钱int oneTimeRest = qian[i] * curQianBuyOneColaZhang - x;// 每次买一瓶可乐,吐出的找零总钱数是oneTimeRest// 一共买的可乐数是curQianBuyColas,所以把零钱去提升后面几种面值的硬币数,// 就是giveRest的含义giveRest(qian, zhang, i + 1, oneTimeRest, curQianBuyColas);// 当前面值去搞定可乐这件事,一共投了几次币puts += curQianBuyOneColaZhang * curQianBuyColas;// 还剩下多少瓶可乐需要去搞定,继续用后面的面值搞定去吧m -= curQianBuyColas;// 当前面值可能剩下若干张,要参与到后续买可乐的过程中去,// 所以要更新preQianRest和preQianZhangzhang[i] -= curQianBuyOneColaZhang * curQianBuyColas;preqianRest = qian[i] * zhang[i];preqianZhang = zhang[i];}return m == 0 ? puts : -1;}// 假设单次买可乐,每次零钱是oneTimeRest// 一共买了times次可乐,谁买的? i-1号面值买的// i... 可能获得零钱,请把张数调整对public static void giveRest(int[] qian, int[] zhang, int i, int oneTimeRest, int times) {for (; i < 3; i++) { // 3种面值zhang[i] += (oneTimeRest / qian[i]) * times;oneTimeRest %= qian[i];}}
