P3868 [TJOI2009]猜数字

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

可以得出(n-a_i=kb_i)

(n-a_iequiv0(mod b_i))

(n equiv a_i (mob b_i))

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

没错就是中国剩余定理

(egin{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=prodlimits_{i=1}^{n}b_i)(M_i=m/b_i)(t_i)是线性同余方程(M_it_iequiv1(mod m_i))的一个解

解为(x=sumlimits_{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;
}
原文地址:https://www.cnblogs.com/pyyyyyy/p/12714615.html