题目链接:
https://loj.ac/problem/2721
https://www.luogu.org/problemnew/show/P4774
显然可以发现每次使用的剑是可以用平衡树来维护,假如杀第\(i\)头龙使用攻击为\(b[i]\)的剑。
龙既然要恢复到0的血量,说明:
\(b[i]*x>=a[i]\)
\(b[i]*x \equiv a[i](mod \; p[i])\)
对于第二个条件我们解一个同余方程组,用扩展中国剩余定理合并为一个同余方程,再根据条件一找到最小的x。注意中间运算会爆\(long long\),要用快速乘。
关于解同余方程:
有解的充要条件是\(gcd(b[i],p[i]) | a[i]\)
我们可以先将\(b,a,p\)同时除以\(gcd(b,a,p)\)再判断除后的\(gcd(b,p)==1\),不满足则无解。
再通过求\(b\)在模\(p\)意义下的逆元化为\(x \equiv ab^{-1}( mod \; p)\)的形式再用CRT合并。
(存在逆元的充要条件是\(gcd(b,p)==1\))。
看代码请移步,蒟蒻写的太烂,以后会更新好一点QWQ。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
void exgcd(ll a,ll b,ll& d,ll& x,ll& y){
if(!b){ d=a; x=1; y=0;}
else{ exgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
ll inverse(ll a,ll n){
ll d,x,y;
exgcd(a,n,d,x,y);
return d==1?(x+n)%n:-1;
}
struct node{
node*ch[2];
int r,cnt,s;
ll v;
int cmp(ll x){
if(v==x) return -1;
else return v<x;
}
void maintain(){s=ch[0]->s+ch[1]->s+cnt;}
};
void rotate(node*&o,int d){
node*k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
node*root,*null=new node();
void insert(node*&o,ll x){
if(o==null){
o=new node();
o->v=x;
o->r=rand();
o->ch[0]=o->ch[1]=null;
o->cnt=1;
}
else{
int d=o->cmp(x);
if(d==-1){o->cnt++,o->s++;return;}
insert(o->ch[d],x);
if(o->ch[d]->r>o->r) rotate(o,d^1);
}
o->maintain();
}
void remove(node*&o,ll x){
int d=o->cmp(x);
if(d==-1){
if(o->cnt>1) {o->cnt--,o->s--;return;}
node*u=o;
if(o->ch[0]!=null&&o->ch[1]!=null) {
d=o->ch[0]->r>o->ch[1]->r;
rotate(o,d),remove(o->ch[d],x);
}
else{
if(o->ch[0]!=null) o=o->ch[0];
else o=o->ch[1];
delete u;
}
}else remove(o->ch[d],x);
if(o!=null) o->maintain();
}
ll kth(node*o,int k){
if(o==null) return 0;
int s=o->ch[0]->s;
if(k>s&&k<=s+o->cnt) return o->v;
else if(k<=s) return kth(o->ch[0],k);
else return kth(o->ch[1],k-s-o->cnt);
}
int rank(node*o,ll x){
ll ans=0;
while(o->v!=x){
if(o->v<x) ans+=o->ch[0]->s+o->cnt,o=o->ch[1];
else o=o->ch[0];
}
return ans+o->ch[0]->s+1;
}
ll getpre(node*o,ll x){
ll ans;
bool k=1;
while(o!=null){
if(o->v<=x) ans=o->v,o=o->ch[1],k=0;
else o=o->ch[0];
}
if(k) return 0;
return ans;
}
ll getnxt(node*o,ll x){
ll ans;
while(o!=null){
if(o->v>x) ans=o->v,o=o->ch[0];
else o=o->ch[1];
}
return ans;
}
ll ksc(ll a,ll n,ll p){
a%=p;n%=p;
ll ans=0;
for(;n;n>>=1,a=(a+a)%p){
if(n&1) ans=(ans+a)%p;
}
return ans;
}
void clear(node* o){
if(o!=null){
clear(o->ch[0]);
clear(o->ch[1]);
delete o;
}
}
ll get(ll a){
int b=getpre(root,a);
if(b==0) b=getnxt(root,a);
return b;
}
ll gcd (ll a,ll b){
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
return (a/gcd(a,b))*b;
}
ll swd[N],_swd[N],a[N],p[N],b[N];
int main(){
// freopen("dragon3.in","r",stdin);
null->s=0;
null->v=0;
root=null;
int n,m,t=1;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
root=null;
ll mx=-2333333333333;
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>>_swd[i];
for(int i=1;i<=m;i++){
cin>>swd[i];
insert(root,swd[i]);
}
ll nowb=get(a[1]);
ll lastp=p[1];
remove(root,nowb);
ll agcd=gcd(gcd(nowb,lastp),a[1]);
nowb/=agcd;
a[1]/=agcd;
lastp/=agcd;
b[1]=nowb;
if(gcd(nowb,lastp)>1){
puts("-1");
clear(root);
continue;
}
nowb=inverse(nowb,lastp);
ll nowa=ksc(a[1],nowb,lastp);
insert(root,_swd[1]);
bool ok=1;
for(int i=2;i<=n;i++){
ll now2b=get(a[i]);
remove(root,now2b);
ll agcd=gcd(gcd(now2b,p[i]),a[i]);
now2b/=agcd;
a[i]/=agcd;
p[i]/=agcd;
b[i]=now2b;
if(gcd(now2b,p[i])>1){
puts("-1");
clear(root);
ok=0;
break;
}
now2b=inverse(now2b,p[i]);
ll now2a=ksc(a[i],now2b,p[i]);
ll d,y11,y22;
exgcd(lastp,-p[i],d,y11,y22);
ll kk=now2a-nowa;
if(kk%d!=0){
puts("-1");
clear(root);
ok=0;
break;
}
ll k=lastp;
lastp=lcm(lastp,p[i]);
nowa=((ksc(ksc((kk/d),y11,lastp),k,lastp)
+nowa)%lastp+lastp)%lastp;
insert(root,_swd[i]);
}
if(!ok) continue;
for(int i=1;i<=n;i++){
ll k=a[i]-b[i]*nowa;
if(k>0){
ll kk=b[i]*lastp;
if(k%kk==0) nowa+=(k/kk);
else nowa+=k/kk+1;
}
}
cout<<nowa<<endl;
}
return 0;
}