【POJ2891】Strange Way to Express Integers-解一元线性同余方程组
测试地址:Strange Way to Express Integers
题目大意:用以下方法表示一个非负整数
做法:这道题需要使用扩展欧几里得来解一元线性同余方程组。
分析题目,实际上题目要求的就是这个同余方程组的最小非负整数解:
我们知道当模数
答案是,我们需要将同余方程一一合并。我们不妨先来探讨怎么把两个同余方程构成的同余方程组合并为一个等价的同余方程。我们知道这种同余方程实际上可以展开变成一个二元一次不定方程,即
这样一步步合并下去即可合并整个方程组,然后就可以得出解了。因为数字较大,所以在一些地方要防止溢出,其次就是要注意计算各个值的顺序,然后我们就完美地解决了这道题。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int n;
ll a1,a2,r1,r2,x0,y0,d;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
ll x0,y0,x1,y1;
x0=1,y0=0;
x1=0,y1=1;
while(a%b)
{
ll tmp,q;
q=a/b;
tmp=x0,x0=x1,x1=tmp-q*x1;
tmp=y0,y0=y1,y1=tmp-q*y1;
tmp=a,a=b,b=tmp%b;
}
d=b,x=x1,y=y1;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
scanf("%lld%lld",&a1,&r1);
bool flag=1;
for(int i=1;i<n;i++)
{
scanf("%lld%lld",&a2,&r2);
if (!flag) continue;
exgcd(a1,a2,d,x0,y0);
if ((r2-r1)%d) {flag=0;r1=-1;continue;}
ll t=a2/d;
x0=(x0*((r2-r1)/d)%t+t)%t; //防止结果是负数
r1=r1+a1*x0;
a1=a1*(a2/d);
}
printf("%lld\n",r1);
}
}