萌新求调,最后三个点输出 -1
查看原帖
萌新求调,最后三个点输出 -1
353688
王熙文楼主2022/11/28 21:19

思路是对于 xi×kiai(modpi)x_i \times k_i \equiv a_i \pmod {p_i} 用 exgcd 求出一组特解,然后之后的同余方程模数应该是 pigcd(pi,ki)\dfrac{p_i}{\gcd(p_i,k_i)},就转化为一个正常的同余方程,最后 exCRT。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int gcd(int a,int b) { return !b?a:gcd(b,a%b); }
int lcm(int a,int b) { return a/gcd(a,b)*b; }
int n,m;
int a[100010],p[100010];
int g[100010];
multiset<int> st;
int k[100010]; // x*k_i=a_i(mod p_i)
pair<int,int> exgcd(int a,int b)
{
	if(!b) return {1,0};
	pair<int,int> lst=exgcd(b,a%b);
	return {lst.second,lst.first-lst.second*(a/b)};
}
pair<int,int> exgcd1(int a,int b)
{
	int g=gcd(a,b);
	return exgcd(a/g,b/g);
}
pair<int,int> exgcd2(int a,int b,int d)
{
	pair<int,int> ans=exgcd1(a,b);
	int g=gcd(a,b);
	return {ans.first*(d/g),ans.second*(d/g)};
}
int nowa,nowb;
bool excrt(int a,int b)
{
	if((a-nowa)%gcd(nowb,-b)) return 1;
	pair<int,int> now=exgcd2(nowb,-b,a-nowa);
	__int128 x1=nowa+(__int128)nowb*now.first;
	nowb=lcm(nowb,b),nowa=(x1%nowb+nowb)%nowb;
	return 0;
}
void solve()
{
	cin>>n>>m;
	for(int i=1; i<=n; ++i) cin>>a[i];
	for(int i=1; i<=n; ++i) cin>>p[i];
	for(int i=1; i<=n; ++i) cin>>g[i];
	st.clear();
	for(int i=1; i<=m; ++i)
	{
		int x; cin>>x;
		st.insert(x);
	}
	int ax=0; // x 必须要大于的数
	for(int i=1; i<=n; ++i)
	{
		auto wz=st.upper_bound(a[i]);
		if(wz!=st.begin()) --wz;
		k[i]=(*wz);
		st.erase(wz),st.insert(g[i]);
		ax=max(ax,(a[i]+k[i]-1)/k[i]);
	}
	for(int i=1; i<=n; ++i)
	{
		if(a[i]%gcd(k[i],p[i])) return cout<<-1<<'\n',void();
		int x1=exgcd2(k[i],p[i],a[i]).first;
		p[i]/=gcd(k[i],p[i]),a[i]=(x1%p[i]+p[i])%p[i];
	}
	nowa=0,nowb=1;
	for(int i=1; i<=n; ++i)
	{
		if(excrt(a[i],p[i])) return cout<<-1<<'\n',void();
	}
	cout<<nowa+nowb*((ax-nowa)/nowb)<<'\n';
}
signed main()
{
	freopen("1.in","r",stdin);
	int t; cin>>t;
	while(t--) solve();
	return 0;
}
2022/11/28 21:19
加载中...