Strange Way to Express Integers——解题报告

一、题目链接:

http://poj.org/problem?id=2891

二、题目大意:

给定 2 n 2n 2n个正整数 a 1 , a 2 , … … , a n a_1,a_2,……,a_n a1a2……an m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1m2...mn,求一个最小的正整数 x x x,满足任意 i ∈ [ 1 , n ] i∈[1,n] i[1,n],都存在 x ≡ a i ( m o d   m i ) x≡a_i(mod\ m_i) xai(mod mi),若无解则输出 − 1 -1 1

三、题目分析:

1.因为此时没有保证 m i m_i mi相互之间是互质关系,所以没有办法使用中国剩余定理,只能考虑其他的方法。
2.我们假设此时已经求出了前 k − 1 k-1 k1个方程的解 x x x。设 M = ∏ i = 1 k − 1 x i M=\begin{matrix} \prod_{i=1}^{k-1} x_i \end{matrix} M=i=1k1xi,而此时显然对于前面的所有 k − 1 k-1 k1个方程来说, x + t × M x + t \times M x+t×M都是方程的解,因为 t × M t \times M t×M对任意 m i ( i ≤ k − 1 ) m_i(i\leq k-1) mi(ik1)取余都为 0 0 0
3.而对于第k个方程来说,要是存在x+t*M是方程的解,那么此解就是前k个方程的通解。所以我们的操作如下:

  • 因为此时要求 x + t × M ≡ a k ( m o d m k ) x + t \times M≡a_k(mod m_k) x+t×Mak(modmk),而方程等价于 t × M ≡ a k − x ( m o d m k ) t \times M≡a_k-x(mod m_k) t×Makx(modmk)
  • 因为 a k − x a_k-x akx已知,所以转化为了一个全新的线性同余方程,此时使用扩展欧几里得算法求出其中一个特解,若无解则直接输出 − 1 -1 1
  • 而求出的特解即 t t t,可以得到 x + t × M ≡ a k ( m o d   m k ) x + t \times M≡a_k(mod\ m_k) x+t×Mak(mod mk)成立,同时 x ′ = x + t × M x'=x + t \times M x=x+t×M同时也是前面 k k k个方程的通解。
  • 重复上述过程直到 k = n k=n k=n运行结束。

4.由于 M M M很容易超 l o n g   l o n g long\ long long long,所以我们一定要注意取余的问题,详细的细节可以看代码。

四、正解代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>

using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(!b)
	{
		x=1;
		y=0;
		return a;
	}
	ll d=exgcd(b,a%b,x,y);
	ll z=x;
	x=y;
	y=z-y*(a/b);
	return d;
}
ll n;
int main()
{
	while(~scanf("%lld",&n))
	{
		ll a,m;
		scanf("%lld%lld",&m,&a);
		ll x=a,M=m;
		bool flag=false;
		for(ll i=2;i<=n;i++)
		{
			ll t1,ty,New;
			scanf("%lld%lld",&m,&a);
			New=((a-x)%m+m)%m;
			ll d=exgcd(M,m,t1,ty);
			if(New%d==0)
				t1=t1*(New/d)%m;
			else
				flag=true;
			x+=t1*M;
			M=M/d*m;
			x=(x%M+M)%M;
		}
		if(!flag)
			printf("%lld\n",x);
		else
			printf("-1\n");
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值