excrt模板
题面很长,仔细读题后就可以发现每次必须打死巨龙,否则就输了
并且每次选择的剑是固定的,可以用set维护
然后问题就转化为求解n个不定方程组成的方程组,其中第i个方程为:
a
i
+
y
∗
p
i
−
x
∗
a
t
k
i
=
0
a_i+y*p_i-x*atk_i=0
ai+y∗pi−x∗atki=0
x
∗
a
t
k
i
−
y
∗
p
i
=
a
i
x*atk_i-y*p_i=a_i
x∗atki−y∗pi=ai
x
∗
a
t
k
i
≡
a
i
(
m
o
d
p
i
)
x*atk_i\equiv a_i(modp_i)
x∗atki≡ai(modpi)
x
≡
a
i
a
t
k
i
(
m
o
d
p
i
)
x\equiv \frac{a_i}{atk_i}(modp_i)
x≡atkiai(modpi)
这是不定方程转同余方程的一般套路
先考虑一个问题,
a
t
k
i
atk_i
atki在
m
o
d
p
i
mod p_i
modpi的逆元:
用exgcd求,因为可能有不存在逆元的情况
再看一部分无解的情况:
设
g
=
g
c
d
(
a
[
i
]
,
a
t
k
[
i
]
,
p
[
i
]
)
g=gcd(a[i],atk[i],p[i])
g=gcd(a[i],atk[i],p[i])
若
g
c
d
(
a
t
k
[
i
]
/
g
,
p
[
i
]
/
g
)
>
1
gcd(atk[i]/g,p[i]/g)>1
gcd(atk[i]/g,p[i]/g)>1则无解,否则一定有解
然后就excrt合并,数据较大,用快速乘防止炸精度
还有一点,需要满足
x
≥
⌈
a
i
a
t
k
i
⌉
x\geq\lceil{\frac{a_i}{atk_i}}\rceil
x≥⌈atkiai⌉,因为攻击必须大于生命值
求出满足条件的x即可
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e5+5;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1,y=0;return a;}
ll res=exgcd(b,a%b,y,x);
y-=x*(a/b);
return res;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
inline ll Inv(ll v,ll mod){
ll x,y,g=exgcd(v,mod,x,y);
if(g>1) return -1;
return (x+mod)%mod;
}
inline ll ksc(ll a,ll b,ll mod){
a=(a%mod+mod)%mod;
b=(b%mod+mod)%mod;
ll res=0;
for(;a;a>>=1,b=(b<<1)%mod) if(a&1LL) res=(res+b)%mod;
return res;
}
multiset<ll>s;
int n,m;
ll a[N],p[N],h[N],inv[N],x[N];
inline bool excrt(ll a1,ll p1,ll a2,ll p2,ll &a,ll &p){
ll x,y,z=a2-a1,g=exgcd(p1,p2,x,y);
if(z%g) return 0;
ll t=z/g;
x=ksc(x,t,p2/g);
p=p1/g*p2;
a=((a1+ksc(x,p1,p))%p+p)%p;
return 1;
}
inline ll solve(){
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) p[i]=read();
for(int i=1;i<=n;i++) h[i]=read();
s.clear();
while(m--) s.insert(read());
for(int i=1;i<=n;i++){
multiset<ll>::iterator it=s.begin();
if((*it)<a[i]) it=--s.upper_bound(a[i]);
inv[i]=*it;s.erase(it);s.insert(h[i]);
}
for(int i=1;i<=n;i++){
ll g=gcd(a[i],gcd(inv[i],p[i]));
inv[i]/=g;p[i]/=g;a[i]/=g;
ll v=Inv(inv[i],p[i]);
if(v<0) return -1;
x[i]=ksc(a[i],v,p[i]);
}
ll W=x[1],M=p[1];
for(int i=2;i<=n;i++) if(!excrt(W,M,x[i],p[i],W,M)) return -1;
for(int i=1;i<=n;i++){
ll val=(a[i]+inv[i]-1)/inv[i];
if(val<=W) continue;
ll k=(val-W+M-1)/M;
W+=k*M;
}
return W;
}
int main(){
int t=read();
while(t--) cout<<solve()<<"\n";
return 0;
}