Processing math: 100%

1. 题目

传送门= ̄ω ̄=

2. 题解

网上一篇题解都搜不到。。。

一份参考代码都没有

问题给出 M,D,L,R,求 LDxmodMR的最小正整数解,数据范围 109

首先判断如果存在 Dx[L,R],(Dx<M)则直接返回答案。

否则说明走一圈(M)的路程之内是无法到达 [L,R]内的。

式子可以写成 LDxM×DxMR

取反:

RM×DxMDxL

这个式子的 Dx可以拆开并且移项到 RL项中,因此整个式子可以对 D取模:

(RmodD)(M×DxMmodD)(LmodD)

然后发现当前这个式子和最开始的 LDxmodMR形式是相同的,但是规模减小了,因此递归处理就可以得到 DxM的值,由此可以推算得到 x的值。

递归的形式和求 gcd是一样的,复杂度 O(ln(n))级别的

如果要感性理解的话呢就是我当前无法一圈内走完。

则设我需要走 y圈,每圈长度为 M

走完以后可以使我最后一次在原点(坐标 0,也可以认为是坐标 M)之前的位置变为 (MymodD)

到达 (MymodD)之后我再跳一步 D就到达原点的右边了

也就是我给当前这次从原点开始的跳跃提供了一个提前量——MymodD

设我从 (MymodD)这个位置开始跳,要跳 k次才能到达 [L,R]内,则:

LDk(MymodD)R

移项:

LDk(MymodD)RDk

这里 k可以随便取,所以你可以理解为[L,R]向左移动 k次,每次移动距离 D,使得坐标负半轴上的点 (MymodD)在区间内

然后把这个式子取反得到:

(RmodD)(MymodD)(LmodD)

(因为 k随便取所以 Dk可以直接替换成取模)

这里的式子和上面直接数学推导得到的式子是一样的,依然是递归求出 y即可

无解情况就是 L>R或者 D=0

注意初始的时候 R要对 M1取 min

代码:

#include <cstdio>
#include <iostream>
#include <cctype>

using namespace std;

template<typename _Tp> inline void IN(_Tp& dig)
{
    char c; bool flag = 0; dig = 0;
    while (c = getchar(), !isdigit(c)) if (c == '-') flag = 1;
    while (isdigit(c)) dig = dig * 10 + c - '0', c = getchar();
    if (flag) dig = -dig;
}

int Dfs(int m, int d, int l, int r)
{
    if (l > r || !d) return -1;
    if (1ll * r / d * d >= l) return (l - 1) / d + 1;
    int x = Dfs(d, m % d, ((-r) % d + d) % d, ((-l) % d + d) % d);
    if (x == -1) return -1;
    return (1ll * m * x + l - 1) / d + 1;
}

int T;

int main(int argc, char const* argv[])
{
    IN(T);
    while (T--)
    {
        int M, D, L, R, G;
        IN(M), IN(D), IN(L), IN(R), R = min(R, M - 1);
        printf("%d\n", Dfs(M, D, L, R));
    }
    return 0;
}
C++
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ

2 条评论

scnucjh · 2020年5月9日 5:39 下午

这个式子的 ?? 可以拆开并且移项到 −? 和 −? 项中,因此整个式子可以对 ? 取模:

为什么可以对 D 取模, 这里还是很不理解

    Remmina · 2020年5月11日 11:48 下午

    好吧我确实是不记得了,想了很久也不记得当时是怎么想的了。
    也许式子写成 LDxMyR 会更容易理解,因为 x,y 之间是独立的。
    其实这里若存在答案,那 y 必然等于 DxM

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注