洛谷传送门
题目描述
现有两组数字,每组 个,第一组中的数字分别为: , ,…, 表示,第二组中的数字分别用 , ,…, 表示。其中第二组中的数字是两两互素的。求最小的非负整数 ,满足对于任意的 , 能被 整除。
输入输出格式
输入格式:
输入数据的第一行是一个整数 ,( )。接下来有两行,第一行是: , ,…, ,第二行是 , ,…,
输出格式:
输出所求的整数 。
输入输出样例
输入样例#1:
3
1 2 3
2 3 5
输出样例#1:
23
说明
所有数据中,第一组数字的绝对值不超过 (可能为负数),第二组数字均为不超过 的正整数,且第二组里所有数的乘积不超过
每个测试点时限 秒
注意:对于C/C++语言,对 位整型数应声明为long long,如使用scanf, printf函数(以及fscanf, fprintf等),应采用 标识符。
解题分析
其实是一道 板题…
大概条件是这样的:
因为 互质, 这就好办了。 设 , 。
对于每个 , 我们可以求出其在 意义下的逆元 , 那么 且 , 我们的任务就完成了, 只需要每一项乘上 就好。
后面的点会直接乘会爆 , 所以就用龟速乘(其实和快速幂差不多)。
可能为负数, 先取模并保证是正数。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 105
#define gc getchar()
#define ll long long
bool neg;
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc)
if(c == '-') neg = true;
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
if(neg) neg = false, x = -x;
}
IN ll qmul(ll a, ll b, ll mod)
{
ll ret = 0, mul = a;
for (R int i = 0; i <= 62; ++i, a = a * 2 % mod)
if(b & (1ll << i)) ret = (ret + a) % mod;
return ret;
}
void exgcd(ll a, ll b, ll &x, ll &y)
{
if(!b) return x = 1, y = 0, void();
exgcd(b, a % b, x, y);
ll buf = x; x = y, y = buf - a / b * y;
}
ll md[MX], rm[MX];
int num;
IN ll CRT()
{
ll M = 1, Mi, x, y, ans = 0;
for (R int i = 1; i <= num; ++i) M *= md[i];
for (R int i = 1; i <= num; ++i)
{
Mi = M / md[i];
exgcd(Mi, md[i], x, y);
x = (x % md[i] + md[i]) % md[i];
ans = (ans + qmul(qmul(x, rm[i], M), Mi, M)) % M;
}
return (ans + M) % M;
}
int main(void)
{
in(num);
for (R int i = 1; i <= num; ++i) in(rm[i]);
for (R int i = 1; i <= num; ++i) in(md[i]), rm[i] = (rm[i] % md[i] + md[i]) % md[i];
printf("%lld", CRT());
}