您的位置:首页 > 其它

POJ 2891 Strange Way to Express Integers

2011-03-03 20:39 281 查看
告诉你k对a,b,x=ai mod bi,求满足条件最小的非负x,如果无解,输出-1

参考:http://scturtle.is-programmer.com/posts/19363.html

http://hi.baidu.com/edwardmj/blog/item/a1cd568087ad4cb26d81197c.html

由于bi,bj不保证互素,不能用直接套中国剩余定理,做法是利用欧几里德扩展定理,将两个等式合并,然后再与其他的等式一一合并

对于x=a1 mod b1,x= a2 mod b2,设x=a1+m*b1

所以b1*m=a2-a1 mod b2,利用欧几里德扩展定理求出最小的非负m,那么x=a1+m*b1就已知,且x最小,如果无解,整个同余式组无解

同时,x+k*b1是所有满足x=a1 mod b1的解,而x+k'*b2又是所有满足x=a2 mod b2的解

那么,将x+k*b1与x+k'*b2合并,得到的式子就是x+k*lcm(b1,b2)

于是,上面两个式子可以用x'=x mod lcm(b1,b2)来替代

最后,就只剩下一个式子了,求得的最小的x就是答案

对于一次同余式ax=b mod n,设d=gcd(a,n),则同余式有解的充要条件为d|b

假设d=a*x'+n*y',则x0=b/d*x'一定为方程组的一个解,且共有d个解,(证明可以参考算法导论)最小正整数解为(x0%n/d+n/d)%(n/d)

代码:

#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
__int64 k,m,t;
__int64 gcd(__int64 a,__int64 b)
{
if(b==0)
return a;
else return (b,a%b);
}
__int64 extend_euclid(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
__int64 d=extend_euclid(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return d;
}
int main()
{
int i,flag;
__int64 p,q,d,a1,a2,b1,b2,x,c;
while(scanf("%I64d",&k)!=EOF)
{
scanf("%I64d%I64d",&b1,&a1);
flag=0;
for(i=0;i<k-1;i++)
{
scanf("%I64d%I64d",&b2,&a2);
if(flag)
continue;
d=extend_euclid(b1,b2,p,q);
c=a2-a1;
if(c%d)
{
flag=1;
continue;
}
t=b2/d;
x=(c/d*p%b2+b2)%t;//  c/d*p可能为负数,要先模一个b2
a1=x*b1+a1;
b1=b1*b2/d;//b1=lcm(b1,b2)
}
if(flag)
puts("-1");
else
printf("%I64d/n",a1);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: