【表达整数的奇怪方式】(中国剩余定理(非互素))

题目:

给定2n个整数a1,a2,…,ana1,a2,…,an和m1,m2,…,mnm1,m2,…,mn,求一个最小的非负整数x,满足∀i∈[1,n],x≡mi(mod ai)∀i∈[1,n],x≡mi(mod ai)。

输入格式

第1行包含整数n。

第2..n行:每i+1行包含两个整数aiai和mimi,数之间用空格隔开。

输出格式

输出最小非负整数x,如果x不存在,则输出-1。
如果存在x,则数据保证x一定在64位整数范围内。

数据范围

1≤ai≤231−11≤ai≤231−1,
0≤mi 1≤n≤251≤n≤25

输入样例:

2
8 7
11 9

输出样例:

31

 

解题报告:之前接触过互素的中国剩余定理,但是这个题目不是互素的啊,所以咱们就应该转化一下思维,利用多个同余方程进行组合求解,是基于exgcd实现的,然后就没有了。(强行理解不易,当作模板记下来吧)

ac代码:

#include
using namespace std;
typedef long long ll;

ll m[1100],r[1100];
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1;y=0;
		return a;
	}
	ll x0,y0;
	ll d=exgcd(b,a%b,x0,y0);
	x=y0;
	y=x0-(a/b)*x;
	return d;
}
ll gcd(ll a,ll b)
{
	if(b==0)
		return a;
	else
		return gcd(b,a%b);
}

ll ex_CRT(int n)
{
	ll a,b,c,c1,c2,x,y,d,N;
	a=m[1];c1=r[1];
	for(int i=2;i<=n;i++)
	{
		b=m[i];
		c2=r[i];
		c=c2-c1;
		d=exgcd(a,b,x,y);
		if(c%d) return -1;
		ll b1=b/d;
		x=((c/d*x)%b1+b1)%b1;
		c1=a*x+c1;
		a=a*b1;
	}
	/*
	if(c1==0)
	{
		c1=1;
		for(int i=1;i<=n;i++)
			c1=c1*m[i]/gcd(c1,m[i]);//如果题目要求要正整数,那么加上一个所有数的最小公倍数 
	}
	*/
	return c1;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&m[i],&r[i]);
	printf("%lld\n",ex_CRT(n));
}

 

你可能感兴趣的:(acm训练,数论)