P3868 [TJOI2009]猜数字

Link

题目描述

现有两组数字,每组 \(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;
}
posted @ 2020-09-15 14:49  genshy  阅读(120)  评论(0)    收藏  举报