题目大意:
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 imes xequiv apmod p)。
首先把atk除过去(atk、a、p都先约去公因数,若约去后atk无逆元,则无解),
然后得到许多形如(xequiv apmod p)的方程,我们要求最小公共解。
用扩展中国剩余定理即可,即用exgcd每次合并两个同余方程。
时间复杂度(O(nlog n))。
C++ Code:
#include<bits/stdc++.h> #define islose(a)if(a)goto die using LoveLive=long long; const int N=100005; template<typename T> 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<typename T> T max(const T a,const T b){return a<b?b:a;} std::multiset<LoveLive>swd; 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 ",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<ans){ int lcm=1; for(int i=1;i<=n;++i)lcm=lcm/gcd(lcm,p[i])*p[i]; if(!aans)aans=lcm;else aans+=(ans-aans+lcm-1)/lcm*lcm; } printf("%lld ",aans); continue; die:puts("-1"); } return 0; }