孙子定理模板题
如果你不知道什么是中国剩余定理,你可以@它。
现有两组数字,每组\(k\)个,第一组中的数字分别用\(a_1,a_2,\dots,a_k\)表示,第二组中的数字分别用\(b_1,b_2,\dots,b_k\)表示。其中第二组的数字是两两互素的。求最小的\(n\in N\),满足对于\(\forall i\in[i,k]\),有\(b_i|(n-a_i)\)。
输入格式
第一行一个整数\(k\)。
第二行\(k\)个整数,表示:\(a_1,a_2,\dots,a_k\)。
第三行\(k\)个整数,表示:\(b_1,b_2,\dots,b_k\)。
输出格式
输出一行一个整数,为所求的答案\(n\)。\(1≤k≤10,∣a_i∣≤10^9,1≤b_i≤6×10^3\prod_{i=1}^k b_i\le 10^{18}\)。
思路:这是孙子定理的模板题,注意数据范围
#include <bits/stdc++.h>
#include <map>
using namespace std;
typedef long long ll;
#define endl '\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define _for(i, a, b) for (int i=(a); i<=(b); i++)
const int INF = 0x7fffffff;
const int MAXN = 1e5 + 10;
ll m[MAXN], a[MAXN], n;
void exgcd(ll a, ll b, ll &x, ll &y){
if(b == 0){
x = 1;
y = 0;
return ;
}
exgcd(b,a%b,x,y);
ll temp = x;
x = y;
y = temp - a / b * y;
return ;
}
ll qmul(ll n, ll a, ll mod){
ll res = 0;
a = a % mod;
while(n){
if(n & 1) res = (res + a) % mod;
n >>= 1;
a = (a + a) % mod;
}
return res % mod;
}
ll CHT(){
ll res = 0, M = 1;
for(int i = 1; i <= n; i++){
M *= m[i];
}
for(int i = 1; i <= n; i++){
ll x, y;
ll Mi = M / m[i];
exgcd(Mi,m[i],x,y);
x = (x % m[i] + m[i]) % m[i];//防止x为负数
res = (res + qmul(qmul(Mi,x,M),a[i],M)) % M;//使用快速乘不然有的会爆long long
}
if(res < 0) res += M;
return res;
}
int main(){
cin >> n;
for(ll i = 1; i <= n; i++){
cin >> a[i];
}
for(int i= 1; i <= n; i++){
cin >> m[i];
}
for(int i = 1; i <= n; i++){
a[i] = (a[i] % m[i] + m[i]) % m[i];
}
cout << CHT();
return 0;
}
给定\(n\)组非负整数\(a_i,b_i\),求解关于\(x\)的方程组的最小非负整数解。
\[\begin{cases} x\equiv b_1(mod\:a_1)\\ x\equiv b_2(mod\:a_2)\\ \dots\\ x\equiv b_n(mod\:a_n)\\ \end{cases} \]输入格式
输入一行包含整数\(n\)。
接下来\(n\)行,每行两个非负整数\(a_i,b_i\)。
输出格式
输出一行,为满足条件的最小非负整数\(x\)。
数据范围
\(1\leq n\leq10^5,1\leq b_i,a_i\leq10^{12}\),保证所有\(a_1\)的最小公倍数不超过\(10^{18}\)。
思路:同样这也是一道模板题,但是我们要注意数据的范围大小,在编写代码时,使用乘法运算结果会有溢出。
#include <bits/stdc++.h>
#include <map>
using namespace std;
typedef long long ll;
#define endl '\n'
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define _for(i, a, b) for (int i=(a); i<=(b); i++)
const int INF = 0x7fffffff;
const int MAXN = 1e5 + 10;
ll n, m[MAXN], a[MAXN];
ll exgcd(ll a, ll b, ll &x, ll &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
ll gcd = exgcd(b,a%b,x,y);
ll temp = x;
x = y;
y = temp - a / b * y;
return gcd;
}
ll qmul(ll n, ll b, ll mod){
ll res = 0;
while(b > 0){//这里使用b是因为防止n为负数
if(b & 1) res = (res + n) % mod;
n = (n + n) % mod;
b >>= 1;
}
return res;
}
int main(){
IOS
cin >> n;
for(int i = 1; i <= n; i++){
cin >> m[i] >> a[i];
}
ll m1 = m[1], a1 = a[1];
ll x, y;
int ok = 1;
for(int i = 2; i <= n; i++){
ll a2 = a[i], m2 = m[i];
ll c = ((a2 - a1) % m2 + m2) % m2;//防止c为负数
ll gcd = exgcd(m1,m2,x,y);
if(c % gcd){ ok = 0; break;}
x = qmul(x,c/gcd,m2);//防止爆long long
a1 = a1 + x * m1;
m1 = m2 / gcd * m1;//先除后成,防止爆long long
a1 = (a1 + m1) % m1;
}
if(ok == 0) cout << -1;
else cout << a1;
return 0;
}