Processing math: 100%

【[NOI2018]屠龙勇士】

发现好像都是化掉系数之后套上ExCrt的板子

这好像是一个真正的扩展扩展中国剩余定理

我们要处理的方程是这样的形式

cixbi(mod ai)

其中c用一个std::multiset处理就好了

好像不是普通excrt可以处理的形式啊

思考一下这个方程的本质是什么,cix=kiai+bi

所以如果我们有两个方程

c1xb1(mod a1)

c2xb2(mod a2)

我们需要像crt那样合并起来

我们开始化柿子了

x=k1a1+b1c1=k2a2+b2c2

所以就有

a2c1k2+b2c1=a1c2k1+b1c2

a2c1k2=a1c2k1+b1c2b2c1

根据贝祖定理,这个方程有解条件是gcd(a2c1,a1c2)|(b1c2b2c1)

如果有解的话,我们设t=gcd(a2c1,a1c2),两边除以t

a2c1k2t=a1c2k1t+b1c2b2c1t

显然我们可以写成一个同余式

a2c1k2tb1c2b2c1t (mod a1c2t)

之后设inv=(a2c1t,a1c2t),即a2c1tmod a1c2t意义下的乘法逆元

两边乘以inv

k2invb1c2b2c1t (mod a1c2t)

改写成等式

k2=invb1c2b2c1t+y×a1c2t

我们把k2回带到c2x=k2a2+b2

c2x=invb1c2b2c1ta2+y×a1c2a2t+b2

再改写成同余式

c2xinvb1c2b2c1t%(a1c2t)a2+b2(mod a1c2a2t)

我们只需要顺次合并这些方程就好了,一旦出现无解就输出1好了

一个坑点是a=1时解出来会是0,好像和实际要求不太一样,所以对于这样情况直接模拟特判就好了

之后因为非常的懒没用快速乘,用了__int128

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define re register
#define maxn 100005
#define LL __int128
#define min(a,b) ((a)<(b)?(a):(b))
#define INF 9999999999999
#define max(a,b) ((a)>(b)?(a):(b))
#define set_it std::multiset<LL>::iterator
std::multiset<LL> s;
int n,m;
LL a[maxn],b[maxn],c[maxn],res[maxn];
LL gcd(LL a,LL b){ return !b?a:gcd(b,a%b);}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
	if(!b) return x=1,y=0,a;
	LL r=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return r;
}
inline LL pre(LL x)
{
	s.insert(x);
	set_it i=s.find(x);
	if(i==s.begin()) return -INF;
	--i;return *i;
}
inline void del(LL x)
{
	set_it i=s.find(x);
	s.erase(i);
}
inline int check(LL x)
{
	if(s.find(x)!=s.end()) return 1;
	return 0;
}
inline LL read()
{
	char c=getchar();
	LL x=0;
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9')
		x=(x<<3)+(x<<1)+c-48,c=getchar();
	return x;
}
inline LL inv(LL a,LL b)
{
	LL x,y;
	LL r=exgcd(a,b,x,y);
	return (x%b+b)%b;
}
void write(LL x)
{
    if(x>9) write(x/10);
    putchar(x%10+48);
}
inline LL did(LL a,LL b)
{
	if(a%b==0) return a/b;
	return a/b+1;
}
inline void tepan()
{
	LL ans=0;
	for(re int i=1;i<=n;i++)
		ans=max(ans,did(b[i],c[i]));
	write(ans),puts("");
}
inline void solve()
{
	s.clear();
	LL x;
	int flag=0;
	n=read(),m=read();
	for(re int i=1;i<=n;i++) b[i]=read();
	for(re int i=1;i<=n;i++) a[i]=read(),flag|=(a[i]!=1);
	for(re int i=1;i<=n;i++) res[i]=read();
	for(re int i=1;i<=m;i++) x=read(),s.insert(x);
	for(re int i=1;i<=n;i++)
	{
		if(check(b[i])) c[i]=b[i],del(b[i]);
		else
		{
			LL now=pre(b[i]);
			del(b[i]);
			if(now==-INF)
			{
				set_it it=s.begin();
				c[i]=*it;
				s.erase(it);
			}
			else c[i]=now,del(now);
		}
		s.insert(res[i]);
	}
	if(!flag)
	{
		tepan();
		return;
	}
	LL a1=a[1],b1=b[1],c1=c[1];
	for(re int i=2;i<=n;i++)
	{
		LL a2=a[i],b2=b[i],c2=c[i];
		LL r=gcd(c2*a1,c1*a2);
		if((b1*c2-b2*c1)%r) 
		{
			puts("-1");
			return;
		}
		if((c2*a1/r)<(c1*a2/r)) std::swap(a1,a2),std::swap(b1,b2),std::swap(c1,c2);
		LL P=a1*c2/r,Inv=inv(c1*a2/r,a1*c2/r);
		b1=((Inv*(((b1*c2-b2*c1)/r)%P+P)%P*a2))+b2;
		a1=a1*a2*c2/r;
		c1=c2;
	}
	LL y;
	if(b1%gcd(a1,c1))
	{
		puts("-1");
		return;
	}
	LL r=exgcd(c1,a1,x,y);
	LL t=a1/r;
	x=(x*(b1/r)%t+t)%t;
	write(x);
	puts("");
}
int main()
{
	int T;
	T=read();
	while(T--) solve();
	return 0;
}
posted @   asuldb  阅读(214)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示