【luoguP3868】猜数字

description

现有两组数字,每组k个,第一组中的数字分别为:a1,a2,...,ak表示,第二组中的数字分别用b1,b2,...,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。


analysis

  • 根据题意可以知道

[ left{ egin{aligned} n-a_1≡0(mod b_1)\ n-a_2≡0(mod b_2)\ ......\ n-a_k≡0(mod b_k) end{aligned} ight. ]

  • 对于(a-b≡0(mod c)),如果(c|a-b),那么(amod c=b)

  • 所以

[ left{ egin{aligned} n≡a_1(mod b_1)\ n≡a_2(mod b_2)\ ......\ n≡a_k(mod b_k) end{aligned} ight. ]

  • 随便用哪种(CRT)都可以,但注意普通(CRT)的乘法每处都要模

code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)

using namespace std;

ll a[MAXN],m[MAXN];
ll n;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if (b==0){x=1,y=0;return a;}
	ll ans=exgcd(b,a%b,y,x);
	y-=x*(a/b);return ans;
}
inline ll mul(ll x,ll y,ll mod)
{
	return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;     
}
inline ll CRT(ll a[],ll m[],ll n)
{
	ll M=1,x,y,ans=0;
	fo(i,1,n)M*=m[i];
	fo(i,1,n)
	{
		ll tmp=M/m[i];exgcd(tmp,m[i],x,y);
		ans=(ans+mul(mul(a[i],x,M),tmp,M))%M;
	}
	return (ans%M+M)%M;
}
inline ll EXCRT(ll a[],ll m[],ll n)
{
	ll M=m[1],x,y,ans=a[1];
	fo(i,2,n)
	{
		ll gcd=exgcd(M,m[i],x,y),tmp=(a[i]-ans%m[i]+m[i])%m[i];
		if (tmp%gcd!=0)return -1;
		x=mul(x,tmp/gcd,m[i]/gcd);
		ans+=x*M,M*=m[i]/gcd,ans=(ans%M+M)%M;
	}
	return (ans%M+M)%M;
}
int main()
{
	n=read();
	fo(i,1,n)a[i]=read();
	fo(i,1,n)m[i]=read();
	printf("%lld
",CRT(a,m,n));
	return 0;
}
原文地址:https://www.cnblogs.com/horizonwd/p/11307695.html