题目描述
现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。
输入输出格式
输入数据的第一行是一个整数k,(1 ≤ k ≤ 10)。接下来有两行,第一行是:a1,a2,...,ak,第二行是b1,b2,...,bk
输出所求的整数n。
也就是求出n,让n满足bi|n-ai。我们将式子转化一下,bi|n-ai => n-aiΞ0(mod bi) => nΞai(mod bi),也就是一个同余方程了。如果只解决这一个,我们可以直接一个扩欧敲下去,但这里有k个方程。我们再看题,题目要求我们求出最小的n满足所有同余方程,并且b1,b2...bn两两互质。这不就是中国剩余定理吗?所以把板子打上去就可以了。这题要注意的是ai可能为负数,不过我们把它转成正的就可以了。还有就是直接乘会爆long long,所以我们还要用到喜闻乐见的龟快速乘。
#include <cstdio> #define maxn 15 using namespace std; long long a[maxn], b[maxn], m[maxn], t[maxn]; inline long long read(){ register long long x(0), f=1; register char c(getchar()); while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); } while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar(); return x*f; } inline long long mul(long long a, long long b, long long c){ long long ans=0; while(b){ if(b&1) ans=(ans+a)%c; a=(a<<1)%c; b>>=1; } return ans; } void ex_gcd(long long a, long long b, long long &x, long long &y){ if(!b) x=1, y=0; else{ long long x1, y1; ex_gcd(b, a%b, x1, y1); x=y1, y=x1-a/b*y1; } } int main(){ long long n=read(); for(register int i=1; i<=n; i++) a[i]=read(); for(register int i=1; i<=n; i++) b[i]=read(); for(register int i=1; i<=n; i++) a[i]=(a[i]%b[i]+b[i])%b[i]; long long tot=1, tmp; for(register int i=1; i<=n; i++) tot*=b[i]; for(register int i=1; i<=n; i++) m[i]=tot/b[i]; for(register int i=1; i<=n; i++) ex_gcd(m[i], b[i], t[i], tmp),t[i]=(t[i]%b[i]+b[i])%b[i]; long long ans=0; for(register int i=1; i<=n; i++) ans=(ans+mul(mul(a[i],m[i],tot),t[i],tot))%tot; ans=(ans+tot)%tot; printf("%lld\n", ans); return 0; }
刚学懂中国剩余定理的可以来肝这个裸题。