题解 P3409 【值日班长值周班长】
CodyTheWolf · · 题解
来自攻略组成员的首发题解:
开头小广告:自己做的一个模板库OwO
算法考察:exGCD的最小正整数解
思路:
相信很多同学读完题都会列出这样的同余方程(或许只有本蒟蒻这样干qwq):
\frac{nx+m}{7}\equiv q (mod p)
(x未知)
首先,这个题目描述有坑。实际上一周的有效天数只有5天。。。(而不是7)
其次,
再者,这里面有个整除,在同余方程里面太难搞了,我们考虑换个表达方式:
nx+(m-1)\equiv py+(q-1)+i(mod 5)
(x,y未知)
考虑到在值周同学的任期范围内,轮到值日的同学就行,但方程左边如果不加i的话,那么右边代表的只是某周的第一天,但是其他天数应该也要考虑上,因此加一个i,i的取值应该是
那我们只需要知道一组最小非负整数解x,y,
诶?貌似就是我们的exGCD板子!但是还有一个未知数i怎么搞呢?范围太小啦,枚举就好,于是我们化式子:
(为了方便,让
但是普通的exGCD x,y是可负的,我们怎么把它转化为最小非负整数呢?(会的dalao可以跳过分割线内的内容了qwq)
关于exGCD的最小正整数解法:
对于方程:
ax+by=c
a(x+tb)+b(y-ta)=c
ax+tab+by-tab=c
ax+by=c
他们是等价的。
所以我们考虑求得一个最大的
这里的
本题另外的坑点:
1.我们最终的答案并不是
2.卡精度:某些变量需要__int128才能通过(建议自己思考一下到底是哪些)
3.
个人推荐难度(一次AC):省选/NOI-
理由:exGCD+卡精度+思维+不低的细节复杂度。
CODE:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef long long int128;
LL n, m, p, q;
inline void Write(__int128 x)
{
if (x > 9)
Write(x / 10);
putchar(x % 10 + '0');
return;
}
inline __int128 exGCD(__int128 a, __int128 b, __int128 &x, __int128 &y)
{
if (!b)
return x = 1, y = 0, a;
__int128 gcd = exGCD(b, a%b, x, y), tx = x;
x = y, y = tx - (a / b) * y;
return gcd;
}
inline __int128 Max(__int128 x, __int128 y)
{
return x > y ? x : y;
}
inline __int128 Min(__int128 x, __int128 y)
{
return x < y ? x : y;
}
signed main(void)
{
while (scanf("%lld %lld %lld %lld", &n, &m, &p, &q) != EOF)
{
m--, q--;
__int128 ans = -1;
for (int i = 0; i < 5; i++)
{
__int128 a = n, b = 5 * p, c = 5 * q + i - m, x, y;
if (c == 0)
{
ans = ans == -1 ? m : Min(ans, m);
continue;
}
__int128 gcd = exGCD(a, b, x, y);
if (c % gcd)
continue;
x *= c / gcd;
__int128 t = b / gcd;
x = (x % t + t) % t;
__int128 temp = n * x + m;
ans = ans == -1 ? temp : Min(ans, temp);
}
if (ans == -1)
puts("Orz mgh!!!");
else
Write(ans + 1), putchar('\n');
}
return 0;
}