题目大意:
n条龙,每条龙有血量a和回血值p,当一条龙血量< 0时,他会不断回血直至≥0。若某一刻龙的血量为0,则该龙死亡。
你有m把剑,每把剑有攻击力atk,攻击一下造成的伤害等于atk。并且你杀死一条龙后会得到一把新的剑。
你必须要按顺序杀掉龙,并且每次选择的剑都是atk小于a且最大的那把(如果都不小于a则选atk最小的那一把),杀死后剑消失。
在打每条龙时,你必须用选择的这把剑攻击K次(对于所有n条龙,K相等),且你必须刚好把它打死。
问通过的最小K。若不存在,输出-1。
解题思路:
首先对于每条龙,攻击它的剑是确定的。我们用multiset维护一下,预处理出对于每条龙要用的剑。
其次,对于每一组数据,p要么为1,要么大于等于a。
我们对于p=1的情况,直接特判即可。
对于p大于等于a的情况,我们相当于得到了n个同余方程\(atk\times x\equiv a\pmod p\)。
首先把atk除过去(atk、a、p都先约去公因数,若约去后atk无逆元,则无解),
然后得到许多形如\(x\equiv a\pmod p\)的方程,我们要求最小公共解。
用扩展中国剩余定理即可,即用exgcd每次合并两个同余方程。
时间复杂度\(O(n\log n)\)。
C++ Code:
#include
#define islose(a)if(a)goto die
using LoveLive=long long;
const int N=100005;
template
inline void read(T&d){
int c=getchar();d=0;
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
}
template
T max(const T a,const T b){return aswd;
int n,m,g[N];
LoveLive a[N],p[N],atk[N];
LoveLive gcd(LoveLive a,LoveLive b){return b?gcd(b,a%b):a;}
LoveLive exgcd(LoveLive a,LoveLive b,LoveLive&x,LoveLive&y){
if(b){
auto G=exgcd(b,a%b,y,x);
y-=a/b*x;
return G;
}
x=1,y=0;
return a;
}
inline LoveLive mul(LoveLive a,LoveLive b,LoveLive p){
auto ans=a*b-(LoveLive)((long double)a/p*b+1e-9)*p;
return(ans+p)%p;
}
LoveLive crt(){
LoveLive A=a[1],P=p[1],x,y,d;
for(int i=2;i<=n;++i){
d=exgcd(P,p[i],x,y);
if((A-a[i])%d)return -1;
A-=P*mul((A-a[i])/d,x,(p[i]/d));
P=P/d*p[i];
A=(A+P)%P;
}
return(A+P)%P;
}
int main(){
int T;
for(read(T);T--;){
swd.clear();
read(n),read(m);
bool p_1=true;
for(int i=1;i<=n;++i)read(a[i]);
for(int i=1;i<=n;++i)read(p[i]),p_1=p_1&&p[i]==1;
for(int i=1;i<=n;++i)read(g[i]);
while(m--){
int p;
read(p);
swd.insert(p);
}
for(int i=1;i<=n;++i){
auto it=swd.upper_bound(a[i]);
if(it!=swd.begin())--it;
atk[i]=*it;
swd.erase(it);
swd.insert(g[i]);
}
LoveLive ans=0,aans;
for(int i=1;i<=n;++i)
ans=max(ans,(a[i]-1)/atk[i]+1);
if(p_1){
printf("%lld\n",ans);
continue;
}
for(int i=1;i<=n;++i){
auto G=gcd(p[i],atk[i]);
islose(a[i]%G);
p[i]/=G,atk[i]/=G,a[i]/=G;
LoveLive x,y;
exgcd(atk[i],p[i],x,y);
x=(x%p[i]+p[i])%p[i];
a[i]=mul(a[i],x,p[i]);
}
aans=crt();
islose(aans==-1);
if(aans