模板:
x =
∑
i
=
1
n
p
i
∗
N
q
i
∗
[
(
N
q
i
)
−
1
]
q
i
\sum_{i=1}^n p_i * \frac N{q_i} * [(\frac N{q_i})^{-1}]_{q_i}
∑i=1npi∗qiN∗[(qiN)−1]qi
int p[maxn],q[maxn],n;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x = 1;
y = 0;
return a;
}
int g = exgcd(b,a%b,y,x);
y -= a/b * x;
return g;
}
int CRT()
{
int x,y,N = 1;
int ans = 0;
for(int i=1;i<=n;i++) N *= q[i];
for(int i=1;i<=n;i++){
int tmp = N / q[i];
int g = exgcd(tmp,q[i],x,y);
int tp = q[i]/g;
x = (x%tp + tp)%tp; //最小非负模逆
ans = (ans + p[i]*tmp*x)%N;
}
return ans%N;
}
模板题:https://www.luogu.org/problem/P3868
题目描述
现有两组数字,每组k个,第一组中的数字分别为:a1,a2,…,ak表示,第二组中的数字分别用b1,b2,…,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。
输入格式
输入数据的第一行是一个整数k,(1 ≤ k ≤ 10)。接下来有两行,第一行是:a1,a2,…,ak,第二行是b1,b2,…,bk
输出格式
输出所求的整数n。
输入
3
1 2 3
2 3 5
输出
23
说明/提示
所有数据中,第一组数字的绝对值不超过109(可能为负数),第二组数字均为不超过6000的正整数,且第二组里所有数的乘积不超过1018
最直接得板子题,唯一注意的式pi可能是负数,预处理 p[i] = (p[i]%q[i]+q[i])%q[i]);
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 10100;
ll p[12],q[12];
int n;
ll mul(ll x,ll y,ll z){
ll sm = (ld)x/z*y;
return ((ull)x*y-(ull)sm*z+z)%z;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x = 1;
y = 0;
return a;
}
ll g = exgcd(b,a%b,y,x);
y -= a/b * x;
return g;
}
void CRT()
{
ll N = 1,x,y,ans = 0;
for(int i=1;i<=n;i++) N *= q[i];
for(int i=1;i<=n;i++){
ll tmp = N / q[i];
ll g = exgcd(tmp,q[i],x,y);
ll tp = q[i]/g;
x = (x%tp + tp)%tp;
ans = (ans+mul(mul(p[i],tmp,N),x,N))%N;
}
printf("%lld\n",ans%N);
}
int main(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&p[i]);
for(int i=1;i<=n;i++){
scanf("%lld",&q[i]);
p[i] = (p[i]%q[i]+q[i])%q[i]; //**
}
CRT();
return 0;
}