[luogu 4777] exCRT

题目传送-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

posted @ 2018-08-08 20:59  functionendless  阅读(179)  评论(0编辑  收藏  举报