P3868 [TJOI2009]猜数字

首先观察式子\(\forall i \in [1,k]\)\(b_i|(n-a_i)\)

可以得出\(n-a_i=kb_i\)

\(n-a_i\equiv0(mod \ b_i)\)

\(n \equiv a_i (mob\ b_i)\)

这个式子是不是很眼熟??

没错就是中国剩余定理

\(\begin{cases}n \equiv a_1 (mob\ b_1)\\n \equiv a_2 (mob\ b_2)\\n \equiv a_3 (mob\ b_3)\\……\\n \equiv a_i (mob\ b_i)\end{cases}\)

然后就变得简单了,由中国剩余定理的知识可知

\(m=\prod\limits_{i=1}^{n}b_i\)\(M_i=m/b_i\)\(t_i\)是线性同余方程\(M_it_i\equiv1(mod \ m_i)\)的一个解

解为\(x=\sum\limits_{i=1}^{n}a_iM_it_i\)

记得用龟速乘

注:上面的中国剩余定理必须在模数两两互质的情况下,如果不互质,请看扩展中国剩余定理

/*
@ author:pyyyyyy
-----思路------
-----debug-------
*/
#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N=2020;
int n;
int a[N],b[N];
int m=1,M[N],t[N];
void exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1;y=0;
		return ;
	}
	exgcd(b,a%b,x,y);
	int z=x;
	x=y;y=(z-y*(a/b));
	return ;
}
int mul(int x,int y,int mod)
{
	int ret=0;
	while(y)
	{
		if(y&1) ret=(ret+x)%mod;
		x=(x+x)%mod;
		y>>=1;
	}
	return ret;
}
int ans;
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=1;i<=n;++i) cin>>b[i];
	for(int i=1;i<=n;++i) m*=b[i];
	for(int i=1;i<=n;++i) M[i]=m/b[i];
	for(int i=1;i<=n;++i)
	{
		int x,y;
		exgcd(M[i],b[i],x,y);
		x=(x%b[i]+b[i])%b[i];
		ans+=mul(a[i],mul(M[i],x,m),m);
		ans%=m;	
	}
	cout<<ans;
	
	return 0;
}
posted @ 2020-04-16 17:58  pyyyyyy  阅读(132)  评论(0编辑  收藏  举报