hdu2662 coin 数学

来源:互联网 发布:软件开发标书 编辑:程序博客网 时间:2024/06/05 04:42

题目链接


题意:

用 a, b 两种面额的硬币去组成更大面额的钱,问哪个面额之后的所有数字都可被组成

例:a = 5, b = 7, 此时 23 之后的数字都可被连续组成, 24 = 5 * 2 + 7 * 2, 25 = 5 * 5, 26 = 5 * 1 + 7 * 3...


解题思路:

(怎么说,我的做法属于碰运气的类型,有个初步的猜想觉得差不多了就去写了写

而这道题事实上是可以推出公式的,正经做法参见 大佬)


因为所有数字都可被连续的构成,那么必有

a * x1 + b * y1 = n

a * x2 + b * y2 = n + 1

故必有

a * x3 + b * y3 = 1 ……(*)

因为 a 与 b 互质,由扩展欧几里得知,(*)式必有解

对转移过程有意义的两组解分别是(1) x1 > 0, y1 < 0 (满足x的最小性) (2) x2 < 0, y2 > 0 (满足y的最小性)

也就是说,第一个开始连续的数字必定不能通过(*)式转移过来,所以第一个连续的数字即为 (x1 - 1) * a + (y2 - 1) * b


还是上面的例子,

a * x + b * y = 1

当a = 5, b = 7, 两组解分别为 (1) x1 = 3, y1 = -2 (2) x2 = -4, y2 = 3

24 的解组为 2 2

加上(1), 得到 5 0,即为 25 的解组

加上(2), 得到 1 3,即为 26 的解组

加上(1), 得到 4 1,即为 27 的解组

……

然而24的解组就不能通过其他任何正整数解组通过加上(1)或(2)转移得到,那么必然有 x < x1, y < y2, 

然后自然而然地就猜想第一个连续的数是 (x1 - 1) * a + (y2 - 1) * b

所以答案就是 (x1 - 1) * a + (y2 - 1) * b - 1


其实这里面有挺多gap的,比如说为什么就能保证这之后一定都连续?

为什么不是 x - 2?


这就是直觉啊

其实就是碰运气

其实就是瞎搞


还是有教训的,比如说这种瞎搞的做法,一旦第一遍交了没过,就很容易动摇...毕竟没有坚实的理论基础

然而后来发现自己mod了1e9+7而题目里面压根没有这个要求(??? 十分糟心


AC代码如下:

#include <cstdio>#include <cstring>typedef long long LL;int x, y;void exgcd(int x, int y, int& x1, int& y1) {    if (y == 0) { x1 = 1; y1 = 0; return; }    exgcd(y, x % y, x1, y1);    int temp = x1;    x1 = y1;    y1 = temp - x / y * y1;}void work() {    int x1, y1;    exgcd(x, y, x1, y1);//    printf("%d %d\n", x1, y1);    LL ans;    if (x1 < 0) {        int x2 = x1 + y;        ans = (LL)(x2 - 1) * x + (LL)(y1 - 1) * y;    }    else {        int y2 = y1 + x;        ans = (LL)(x1 - 1) * x + (LL)(y2 - 1) * y;    }    printf("%lld\n", ans - 1);}int main() {    int T;    scanf("%d\n", &T);    while (scanf("%d%d", &x, &y) != EOF) work();    return 0;}