B 一个小问题
链接:https://www.nowcoder.net/acm/contest/75/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
uu遇到了一个小问题,可是他不想答。你能替他解决这个问题吗?
问题:给你k对a和r是否存在一个正整数x使每队a和r都满足:x mod a=r,求最小正解x或无解。
问题:给你k对a和r是否存在一个正整数x使每队a和r都满足:x mod a=r,求最小正解x或无解。
输入描述:
第一行是正整数k(k<=100000) 接下来k行,每行有俩个正整数a,r(100000>a>r>=0)
输出描述:
在每个测试用例输出非负整数m,占一行。 如果有多个可能的值,输出最小的值。 如果没有可能的值,则输出-1。
这是一个裸crt模板,前提条件是a,r不互质。
先补充下中国剩余定理:
比如一个整数n除3余2,x除5余3,x除7余2,求最小的整数n。
设 n%3=2,n%5=3,n%7=2
lcm = 3*5*7 = 105
求解过程:
(lcm/3)*x1除3余数为1,即(lcm/3)*x1+3y1==1
(lcm/5)*x2除5余数为1,即(lcm/5)*x2+5y2==1
(lcm/7)*x3除7余数为1,即(lcm/7)*x3+7y3==1
求出 x1 = 2, x2 = 1,x3 = 1.
M = x1*(lcm/3)*2+x2*(lcm/5)*3+x3*(lcm/7)*2==70*2+21*3+15*2==233
ans = M % lcm =233 % 105 =23;
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <stdlib.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define PI 3.1415926535897932
#define e 2.71828182845904523
const int maxn = 1e5+15;
ll a[maxn],r[maxn],n;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b)d=a,x=1,y=0;
else exgcd(b,a%b,d,y,x),y-=x*(a/b);
}
ll getinv(ll a,ll p)
{
ll d,x,y;
exgcd(a,p,d,x,y);
return (x+p)%p==0?p:(x+p)%p;
}
bool merge(ll &a1,ll &m1,ll a2,ll m2){
ll c,d,x,a3,m3;
c=a2-a1;
d=__gcd(m1,m2);
if (c%d!=0) return false;
c=c/d;m1=m1/d;m2=m2/d;
x=getinv(m1,m2);
x=(x*c)%m2;
x=x*(m1*d)+a1;
m3=m1*m2*d;
a3=(x%m3+m3)%m3;
a1=a3;m1=m3;
return true;
}
ll CRT(){
ll A=a[1],M=r[1];
for (int i=2;i<=n;i++)
if (!merge(A,M,a[i],r[i]))
return -1;
return (A%M+M)%M;
}
int main()
{
while(scanf("%lld",&n)!=EOF){
for(int i=1;i<=n;i++){
scanf("%lld%lld",&r[i],&a[i]);
}
printf("%lld\n",CRT());
}
return 0;
}