不知道为什么,但是有负数就一定要先转换为正数(总之转换成正数一定不会错,因为重新得到的数在模意义下和原来相同)
比如说exgcd求逆元就要转换为最小正整数!!!
反正在同余问题的求解过程中出现了负数就转化为负数
然后因为最后乘起来会爆long long 要用快速加边加边模
还有 在能确定复杂度的前提下能开long long 就开
还有, 把模数全乘起来,是求最小公倍数,这一点在拓展中国剩余定理里也有体现(事实上拓展剩余代码中用的是最小公倍数)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100;
long long m[MAXN],t[MAXN],k,a[MAXN],b[MAXN];
long long ans;
typedef long long ll;
ll x, y, gcdd, ms;
void exgcd(ll a, ll b, ll &gcdd, ll &x, ll &y) {//在这里引用的值都要是全局的,并且参数名和全局变量名相同
if(!b) {
x = 1, y = 0;
gcdd = a;
return;
}
exgcd(b, a%b, gcdd, x, y);
int z = x;
x = y;
y = z - a/b*y;
}
ll qmul(ll a, ll b, ll mod) {
ll ans = 0;
for(; b; b>>=1) {
if(b & 1) {
ans = (ans + a) % mod;
}
a = (a + a) % mod;
}
return ans;
}
int main() {
cin >> k;
for(int i=1; i<=k; i++) {
cin >> a[i];
}
ms = 1;
for(int i=1; i<=k; i++) {
cin >> b[i];
ms *= b[i];
a[i] = (a[i]%b[i] + b[i])%b[i];//反正在同余里面出现负数一般都要转换为正数
}
for(int i=1; i<=k; i++) {
m[i] = ms / b[i];
exgcd(m[i], b[i], gcdd, x, y); //在纸上要想好变量名再写,纸上公式是什么变量名,程序里就写什么,避免混淆
t[i] = (x%b[i] + b[i]) % b[i];
}
for(int i=1; i<=k; i++) {
ans = ((ans+qmul(qmul(m[i], t[i], ms), a[i], ms))%ms + ms) % ms;
}
cout << (ans%ms + ms) % ms;
return 0;
}