题目链接:

http://poj.org/problem?id=2891(裸题)
像这种
X % 8 = 7 X\%8=7 X%8=7
X % 11 = 9 X\%11=9 X%11=9
X X X等于多少?

阔以写成:
X = 8 k 1 + 7 X=8k_1+7 X=8k1+7
X = 11 k 2 + 9 X=11k_2+9 X=11k2+9
所以: 8 k 1 + 7 = 11 k 2 + 9 8k_1+7=11k_2+9 8k1+7=11k2+9
即: 8 k 1 11 k 2 = 2 8k_1-11k_2=2 8k111k2=2
这个式子我们就阔以用 e x g c d exgcd exgcd求出 k 1 k1 k1
要注意的是:
e x g c d exgcd exgcd求的是 8 k 1 + 11 k 2 = g c d ( 8 , 11 ) 8k_1+11k_2=gcd(8,11) 8k1+11k2=gcd(8,11)的解
也就是 8 k 1 + 11 k 2 = 1 8k_1+11k_2=1 8k1+11k2=1的解: k 1 = 4 , k 2 = 3 k_1=-4,k_2=3 k1=4,k2=3

而我们这里

①:

中间是减号,但是没有关系,阔以看成 8 k 1 + 11 ( k 2 ) = 1 8k_1+11(-k_2)=1 8k1+11(k2)=1,求出来的 k 2 k_2 k2添个负号就行了,也就是说 8 k 1 11 k 2 = 1 8k_1-11k_2=1 8k111k2=1的解为: k 1 = 4 , k 2 = 3 k_1=-4,k_2=-3 k1=4,k2=3

②:

我们的这里的 2 2 2 g c d ( 8 , 11 ) gcd(8,11) gcd(8,11)的两倍,那么我们直接在原答案上乘个 2 2 2倍就行了,也就是说
8 k 1 11 k 2 = 2 8k_1-11k_2=2 8k111k2=2的解为: k 1 = 8 , k 2 = 6 k_1=-8,k_2=-6 k1=8,k2=6

③:

那万一是 g c d gcd gcd 1.5 1.5 1.5倍怎么办?那 k 1 = 6 , k 2 = 4.5 k_1=-6,k_2=-4.5 k1=6,k2=4.5么?这样求出来的就不是整数了,而我们要的是整数解,所以:方程的右边不是 g c d gcd gcd的整数倍时:无解

好现在我们求出了 k 1 , k 2 k_1,k_2 k1,k2,随便选一个代回去就能得到 X X X,(一般都选 k 1 k_1 k1,因为 k 2 k_2 k2说不定还要添个负号,挺麻烦的)
那么 X = 8 ( 8 ) + 7 = 57 X=8*(-8)+7=-57 X=8(8)+7=57
为啥是个负的喃?
因为, k 1 , k 2 k_1,k_2 k1,k2是一组解,阔以随便选,只是要满足 8 k 1 11 k 2 = 2 8k_1-11k_2=2 8k111k2=2那就随便选
而且阔以发现 k 1 k_1 k1只能加减 l c m ( 8 , 11 ) 11 \frac{lcm(8,11)}{11} 11lcm(8,11)这么多, k 2 k_2 k2只能加减 l c m ( 8 , 11 ) 8 \frac{lcm(8,11)}{8} 8lcm(8,11)这么多
因此,假如某一次求得的 k 1 k_1 k1太大了,继续下一步操作就有阔能爆long long,因此阔以先 % \% %一个 l c m ( 8 , 11 ) 11 \frac{lcm(8,11)}{11} 11lcm(8,11)让他变小
而且随便代一个 k 1 k_1 k1就是一个 X X X,这不就是通解特解的概念么?
那么 X X X就有一个通解: X = k l c m ( 8 , 11 ) 11 + X 0 X=k*\frac{lcm(8,11)}{11}+X_0 X=k11lcm(8,11)+X0
X 0 便 k 1 X_0就是随便代一个k_1得到的特解 X0便k1
比如我取 k 1 = 6 , X 0 = 57 k_1=-6,那么X_0=-57 k1=6,X0=57
通解就是 X = k 8 57 X=k*8-57 X=k857
阔步阔以看成是 X % 8 = 57 X\%8=-57 X%8=57
诶~把上面两个方程化成了一个方程
同余方程就是这样,两个两个的化,最后只剩一个方程,再取合适的 k 1 k1 k1就行了

/*poj2891*/
#include"iostream"
using namespace std;
typedef  long long LL;
LL exgcd(LL a, LL b, LL &x, LL &y,LL c)
{
    if (b == 0)
    {
        x = c;
        y = 0;
        return a;
    }

    LL d = exgcd(b, a % b, x, y,c);
    LL t = x;
    x = y;
    y = t - a / b * y;
    return d;
}
int main()
{
    LL N;
    while(cin>>N)
    {
        LL A,R,a,r,res;
        LL x,y;
        int flag=0;
        cin>>A>>R;
        for(int i=2;i<=N;i++)
        {
            cin>>a>>r;
            LL d=exgcd(A,a,x,y,1);
            if((r-R)%d)flag=1;

            LL lcm=A/d*a;
            x*=(r-R)/d;
            x%=lcm/A;//这里就是x太大,继续下一步计算有可能爆long long的地方
            res=A*x+R;
            res=(res%lcm+lcm)%lcm;
            A=lcm,R=res;
        }
        if(flag)cout<<-1<<endl;
        else cout<<res<<endl;
    }
}

为了以后方便使用,我用pair把封装起来了

#include"iostream"
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
const int MOD=1e9+7;
const LL inf=1e15;
LL exgcd(LL a, LL b, LL &x, LL &y,LL c)
{
	if (b == 0)
	{
		x = c;
		y = 0;
		return a;
	}
	LL d = exgcd(b, a % b, x, y,c);
	LL t = x;
	x = y;
	y = t - a / b * y;
	return d;
}
pair<LL,LL> solve(pair<LL,LL> p1,pair<LL,LL> p2)//计算两个同余方程组,返回的也是pair
{
	LL m1=p1.first,r1=p1.second;
	LL m2=p2.first,r2=p2.second;
	LL x,y;
	LL d=exgcd(m1,m2,x,y,1);
	if((r2-r1)%d)return make_pair(inf,inf);//无解情况
	LL lcm=m1/d*m2;
	x*=(r2-r1)/d;
	x%=lcm/m1;//x可能太大,模一下
	LL res=m1*x+r1;
	res=(res%lcm+lcm)%lcm;
	return make_pair(lcm,res); 

}
pair<LL,LL>a[maxn];//用pair封装,first是模数,second是余数
int main()
{
	int N;
	while(cin>>N)
	{
		for(int i=1; i<=N; i++)
		{
			LL t1,t2;
			cin>>t1>>t2;
			a[i]=make_pair(t1,t2);
		}
		pair<LL,LL>res=a[1];
		int flag=0;
		for(int i=2;i<=N;i++)
		{
			res=solve(res,a[i]);
			if(res.first==inf)
			{
				flag=1;
				break;
			}
		}
		if(flag)cout<<-1<<endl;
		else cout<<res.second<<endl;
	}
}