洛谷 P3868 [TJOI2009]猜數字【中國剩餘定理】

思路

中國剩餘定理 + 快速乘

題目要求找到最小的nNn\in \N,滿足對於i[1,k]\forall i\in [1,k],有bi(nai)b_i | (n-a_i)

我們試着來轉化一下這個式子

bi(nai)b_i|(n-a_i),也就是說(nai)(n-a_i)在模bib_i意義下同餘00,即nai0(mod bi)n - a_i\equiv 0(\text{mod}\ b_i),進一步轉化,就能得到nai(mod bi)n\equiv a_i(\text{mod}\ b_i)

這個式子是不是很眼熟?沒錯,就是中國剩餘定理的式子,因爲題目中已經保證了bib_i兩兩互素,所以我們就可以直接套中國剩餘定理的板子了

N=i=1nbiN=\prod_{i=1}^nb_iMi=N/biMi=N/b_ixix_i是線性同餘方程Mixi1(mod bi)M_ix_i≡1(\text{mod}\ b_i)的一個解(即MiMi的逆元),最後的解即爲ans=i=1kaiMixians=\sum\limits_{i=1}^ka_iM_ix_i

那麼這樣就完了嘛?

此題終結其實不然

這樣交上去之後,會發現只有九十分,最後一個點WAWA了,因爲這題要用快速乘,於是寫上快速乘

那麼這樣就完了嘛?

此題終結其實也不然

又交上去之後,發現還是九十分,不過這次錯的點是第二個了。

這是爲什麼呢?

看題目條件:ai109∣a_i∣≤10^9

什麼意思呢?意思就是aia_i可能是負的!(出題人真是用心良苦

處理的方法就是:快速乘傳參時取模

那麼這樣就完了嘛?

興沖沖的交上去,終於滿分了,沒錯,這次真完了

代碼

/*
Author:loceaner
中國剩餘定理板子題 
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章