Description
Solution
首先,我们使用的武器和得到的武器是一定的,与选择的攻击次数无关,所以我们只需要一个(multiset)模拟整个过程就能预处理面对每条龙所选择的武器。
容易发现要让巨龙在回血一定次数后死亡就类似于一个取模操作,设面对第(i)条龙是武器的攻击力为(atk_i),于是有(x imes atk_iequiv a_ipmod {p_i})
于是原问题就等价于一个方程组。。。等价吗?
当(a_i> p_i)的时候,攻击(k)次有可能虽然满足上面这个方程,但是(x imes atk_i<a_i)!,这并不会让巨龙死亡。
怎么办呢?增加一个限制条件?仔细分析数据范围,你会发现:所有没有保证(a_ile p_i)的数据都保证(p_i=1),这种情况下答案显然是(Max_{i=1}^{n}lceil frac{a_i}{atk_i} ceil),直接特判即可。
回到上面的方程,(x imes atk_iequiv a_ipmod {p_i}),我们很想将它化成一个(exCRT)能求解的形式,即(xequiv ypmod{p_i}),于是将原方程化为(x imes atk_i+b imes p_i=a_i),(exgcd)求出它的解即可改写成一次项系数为(0)的方程,注意这个方程可能无解,需要特判。
一波操作之后,我们终于化成了我们熟悉的形式,(exCRT)求解即可。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int T,n,m;
ll a[N],p[N],at[N],r[N],v[N<<1];
inline void init(){
multiset<ll> s;
for(int i=1;i<=m;++i) s.insert(v[i]);
for(int i=1;i<=n;++i){
multiset<ll>::iterator it=s.upper_bound(a[i]);
if(it!=s.begin()) it--;
at[i]=*it;s.erase(it);
s.insert(v[m+i]);
}
}
inline void exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return ;}
exgcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
}
int flag;
inline ll add(ll x,ll y,ll mod){return (x+y)%mod;}
inline ll dec(ll x,ll y,ll mod){return ((x-y)%mod+mod)%mod;}
inline ll mul(ll x,ll y,ll mod){
ll z=(long double)x/mod*y;
return ((x*y-z*mod)%mod+mod)%mod;
}
inline void getans(int tp,ll a,ll b,ll c,ll &x,ll &y,ll &mod){
ll g=__gcd(a,b);
if(c%g){x=-1;return ;}
if(tp==1) mod/=g;
exgcd(a,b,x,y);
ll t=c/g;
x=mul(x,t,mod);y=mul(y,t,mod);
}
inline ll gcd(ll x,ll y){return (y==0)?x:gcd(y,x%y);}
inline ll excrt(){
for(int i=1;i<=n;++i){
ll y;
flag=0;getans(1,at[i],p[i],a[i],r[i],y,p[i]);
if(r[i]==-1) return -1;
}
for(int i=2;i<=n;++i){
ll x,y;
ll nmod=(p[i-1]/gcd(p[i-1],p[i]))*p[i];
getans(2,p[i-1],p[i],dec(r[i],r[i-1],nmod),x,y,nmod);
p[i]=nmod;r[i]=add(mul(x,p[i-1],nmod),r[i-1],nmod);
if(r[i]==-1) return -1;
}
return r[n];
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
int flag=0;
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i){
scanf("%lld",&p[i]);
if(p[i]!=1) flag=1;
}
for(int i=1;i<=n;++i) scanf("%lld",&v[m+i]);
for(int i=1;i<=m;++i) scanf("%lld",&v[i]);
init();
if(!flag){
ll ans=0;
for(int i=1;i<=n;++i){
ll t=a[i]/at[i];if(a[i]%at[i]) ++t;
ans=max(ans,t);
}
printf("%lld
",ans);
continue;
}
ll ans=excrt();
if(ans==-1) puts("-1");
else printf("%lld
",ans);
}
return 0;
}