题目链接:
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
8k1−11k2=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 8k1−11k2=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
8k1−11k2=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
8k1−11k2=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=k∗11lcm(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=k∗8−57
阔步阔以看成是
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;
}
}