题目传送-Luogu4777
题目传送-POJ2891
题意:
给若干同余方程组
\[\begin{cases}x&\equiv&x_1&\pmod {p_1}\\x&\equiv&x_2&\pmod {p_2}\\ &&\vdots\\x&\equiv&x_n&\pmod {p_n}\end{cases}\]
求最小的非负整数解\(x\),如果无解输出\(-1\)
题解:
exCRT裸题,算法学习见->我的另一篇博客
过程:
luogu:部分操作需要用到快速乘
POJ:多组数据+禁止__gcd+不告诉你n=100000
代码:
只给出luogu代码
const int N=100010;
int n;
inline void exgcd(ll a,ll b,ll &x,ll &y) {if(!b) {x=1; y=0; return;} exgcd(b,a%b,y,x); y-=a/b*x;}
inline ll lcm(ll a,ll b) {return a/__gcd(a,b)*b;}
inline ll Up(ll x,ll y) {return x/y+(x%y!=0);}
inline ll Mul(ll x,ll y,ll P) {
// printf("%lld %lld %lld\n",x,y,P);
ll ret=0; y%=P;
for(;y;y>>=1,x=x+x) {
// puts("?");
if(x>=P) x-=P;
if(y&1) {
ret=ret+x;
if(ret>=P) ret-=P;
}
}
return ret;
}
struct FUNCTION {
ll k,r;
inline void in() {
read(k); read(r);
}
}f[N];
bool fl=1;
inline FUNCTION Merge(FUNCTION a,FUNCTION b) {
ll z=b.r-a.r,x1,x2,g=__gcd(a.k,b.k); exgcd(a.k,b.k,x1,x2);
if(z%g!=0) {puts("-1"); fl=0; return;} ll tim=z/g;
if(tim<0) {x1=-x1; tim=-tim;}
if(x1<0) {
ll add=b.k/g;
x1+=add*Up(-x1,add);
// assert(x1>=0);
}
// assert(x1>=0);
FUNCTION ret;
ret.k=lcm(a.k,b.k);
ret.r=Mul(a.k,Mul(x1,tim,ret.k),ret.k)+a.r;
// assert(ret.r>=0);
return ret;
}
signed main() {
read(n);
for(int i=1;i<=n;i++) f[i].in();
for(int i=2;i<=n;i++) {
f[1]=Merge(f[1],f[i]);
if(!fl) return 0;
}
printf("%lld\n",f[1].r);
return 0;
}
用时:30min