hdu 3579

蛋疼的一题啊,为了这题先去学了中国剩余定理(比较简单),然后又去学了拓展欧几里得,推了好久的公式,终于弄明白了,然后又去研究怎么求解线性方程组,终于把这题过了。

拓展欧几里得我就不讲了,讲一下这题怎么解方程组的,网上只有代码,没有说明白怎么推的。我们先可以先找两个同余方程 设通解为N,N=r1(mod(m1)),N=r2(mod(m2)),显然可以化为k1*m1+r1=k2*m2+r2;--->k1*m1+(-k2*m2)=r2-r1;设a=m1,b=m2,x=k1,y=(-k2),c=r2-r1方程可写为ax+by=c;由欧几里得解得x即可,那么将x化为原方程的最小正整数解,(x*(c/d)%(b/d)+(b/d))%(b/d);这里看不懂的去看解模线性方程。那么这个x就是原方程的最小整数解。所以N=a*(x+n*(b/d))+r1====N=(a*b/d)*n+(a*x+r1),这里只有n为未知数所以又是一个N=(a*x+r1)(mod(a*b/d))的式子,然后只要不断的将两个式变成一个式子,最后就能解出这个方程组的解。

Run IDSubmit TimeJudge StatusPro.IDExe.TimeExe.MemoryCode Len.LanguageAuthor
52962552012-01-26 17:12:50Accepted35790MS316K1055 BG++xym2010

#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#define LL long long
using namespace std;
const int size=100005,MAX=1<<30,MIN=-(1<<30);
LL m[10],r[10];
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
	if(b==0)
	{
		x=1,y=0,d=a;
	}
	else
	{
		ex_gcd(b,a%b,d,y,x);
		y-=x*(a/b);
	}
}
LL gcd(LL a,LL b)
{
	return b==0?a:gcd(b,a%b);
}
LL china_remain(int n)
{
	LL a,b,c,c1,c2,x,y,d,N;
	a=m[0];c1=r[0];
	for(int i=1;i<n;i++)
	{
		b=m[i];c2=r[i];
		ex_gcd(a,b,d,x,y);
		c=c2-c1;
		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)//当余数都为0
	{
		c1=1;
		for(int i=0;i<n;i++)
			c1=c1*m[i]/gcd(c1,m[i]);
	}
	return c1;
}
int main()
{
	int T,n;
	scanf("%d",&T);
	for(int t=1;t<=T;t++)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
			scanf("%lld",&m[i]);
		for(int i=0;i<n;i++)
			scanf("%lld",&r[i]);
		cout<<"Case "<<t<<": "<<china_remain(n)<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值