洛谷 P3868 [TJOI2009]猜数字

洛谷 P3868 [TJOI2009]猜数字

思路

中国剩余定理 + 快速乘

题目要求找到最小的\(n\in \N\),满足对于\(\forall i\in [1,k]\),有\(b_i | (n-a_i)\)

我们试着来转化一下这个式子

\(b_i|(n-a_i)\),也就是说\((n-a_i)\)在模\(b_i\)意义下同余\(0\),即\(n - a_i\equiv 0(\text{mod}\ b_i)\),进一步转化,就能得到\(n\equiv a_i(\text{mod}\ b_i)\),转化到多个式子就是

\[\begin{equation} \left\{ \begin{array}{lr} n \equiv a_1 (\text{mod}\ b_1)\\ n \equiv a_2 (\text{mod}\ b_2)\\……\\ n \equiv a_k (\text{mod}\ b_k) \end{array} \right. \end{equation}\]

这个式子是不是很眼熟?没错,就是中国剩余定理的式子,因为题目中已经保证了\(b_i\)两两互素,所以我们就可以直接套中国剩余定理的板子了

\(N=\prod_{i=1}^nb_i\)\(Mi=N/b_i\)\(x_i\)是线性同余方程\(M_ix_i≡1(\text{mod}\ b_i)\)的一个解(即\(Mi\)的逆元),最后的解即为\(ans=\sum\limits_{i=1}^ka_iM_ix_i\)

那么这样就完了嘛?

此题终结其实不然

这样交上去之后,会发现只有九十分,最后一个点\(WA\)了,因为这题要用快速乘,于是写上快速乘

那么这样就完了嘛?

此题终结其实也不然

又交上去之后,发现还是九十分,不过这次错的点是第二个了。

这是为什么呢?

看题目条件:\(∣a_i∣≤10^9\)

什么意思呢?意思就是\(a_i\)可能是负的!(出题人真是用心良苦

处理的方法就是:快速乘传参时取模

那么这样就完了嘛?

兴冲冲的交上去,终于满分了,没错,这次真完了

代码

/*
Author:loceaner
中国剩余定理板子题 
*/
#include 
#include 
#include 
#include 
#include 
#define int long long
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, N = 1, b[A], a[A], ans;

inline int mul(int n, int m, int mod) {
	int res = 0;
	while (m) {
		if (m & 1) res = (res + n) % mod;
		n = (n + n) % mod, m >>= 1;
	}
	return res;
}

inline void exgcd(int a, int b, int &x, int &y) {
	if (!b) x = 1, y = 0;
	else exgcd(b, a % b, y, x), y -= a / b * x;
}

signed main() {
	n = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= n; i++) b[i] = read(), N *= b[i];
	for (int i = 1; i <= n; i++) {
		int x, y, Mi = N / b[i];
		exgcd(Mi, b[i], x, y);
		ans = (ans + mul(mul(Mi, x % N + N, N), a[i] % N + N, N) % N + N) % N; 
	}
	cout << ans % N << '\n';
	return 0;
}

你可能感兴趣的:(洛谷 P3868 [TJOI2009]猜数字)