P3868 [TJOI2009]猜数字
题目描述
现有两组数字,每组 \(k\) 个。
第一组中的数字分别用 \(a_1,a_2,\cdots ,a_k\) 表示,第二组中的数字分别用 \(b_1,b_2,\cdots ,b_k\) 表示。
其中第二组中的数字是两两互素的。求最小的 \(n\in \mathbb{N}\),满足对于 \(\forall i\in [1,k]\),有 \(b_i | (n-a_i)\)。
输入格式
第一行一个整数 \(k\)。
第二行 \(k\) 个整数,表示 \(a_1,a_2,\cdots ,a_k\)。
第三行 \(k\) 个整数,表示 \(b_1,b_2,\cdots ,b_k\)。
输出格式
输出一行一个整数,为所求的答案 \(n\)。
输入输出样例
输入 #1
3
1 2 3
2 3 5
输出 #1
23
说明/提示
对于 \(100%\) 的数据:
\(1\le k \le 10\),\(|a_i|\le 10^9\),\(1\le b_i\le 6\times 10^3\),\(\prod_{i=1}^k b_i\le 10^{18}\)。
裸的 CRT 的模板题。
先化简一下柿子:
对于 \(b_i \mid (n-a_i)\) 可以写成 \(n-a_i = k \times b_i\)
然后移项可得 \(n = k \times b_i + a_i\)
也可以写成: \(n\equiv a_i \bmod b_i\)
然后就可以直接套用中国剩余定理的板子啦。
最后的答案就是 \(\displaystyle\sum_{i=1}^{n} a_i M_i {M_i}^{-1}\) \(M_i^{-1}\) 即为 \(M_i\) 在 \(\bmod\) \(b_i\) 的逆元
一个比较坑的地方就是这道题要写慢速乘。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
LL n,a[20],m[20],lcm = 1,ans,x,y;
inline LL read()
{
LL s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
return s * w;
}
void exgcd(LL a,LL b,LL &x,LL &y)//exgcd 求逆元
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
exgcd(b,a%b,y,x);
y -= (a/b) * x;
}
LL msc(LL a,LL b,LL p)//慢速乘
{
LL res = 0;
for(; b; b >>= 1)
{
if( b & 1) res = (res + a) % p;
a = a * 2 % p;
}
return res;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++)
{
m[i] = read();
lcm *= m[i];
}
for(int i = 1; i <= n; i++)
{
x = 0, y = 0;
exgcd(lcm/m[i],m[i],x,y);
if(x < 0) x = (x % m[i] + m[i]) % m[i];
ans = (ans + msc(msc(a[i],x,lcm), (lcm/m[i]),lcm)) % lcm;
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号