Luogu P4774 / LOJ2721 【[NOI2018]屠龙勇士】
真是个简单坑题...++
前置:
exgcd
,exCRT
,STL-multiset
读完题不难发现,攻击每条龙用的剑都是可以确定的,可以用multiset
求。攻击最少显然应该对于每一条龙都操作一次,即攻击\(x\)次。设对于第\(i\)条龙,攻击时使用的剑的攻击力为\(us_i\),生命值为\(hp_i\),恢复能力为\(rh_i\),则\(us_ix\equiv hp_i\pmod{rh_i}\)。然后仔细阅读数据范围和提示,会发现存在\(hp_i>rh_i\)的情况,此时\(rh_i=1\),也即求\(\max\{\Large\lceil\frac{hp_i}{us_i}\rceil\normalsize\}\)。对于\(hp_i\leq rh_i\)的情况,可以直接用exCRT
求答案。而exCRT
适用于\(x\)系数为\(1\)的情况,此处需要用exgcd
求出\(\large\frac{hp_i}{us_i}\normalsize\pmod{rh_i}\),转化为\(x\equiv a_i\pmod{p_i}\)形式。剩下的就只需要exCRT
板子了。可能会爆long long
的乘法转用龟速乘就好了。
#include<bits/stdc++.h>
using namespace std;
void qread(long long &xx){
xx=0;int ch=getchar();
while(ch<'0'||ch>'9'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
xx=xx*10+ch-'0';
ch=getchar();
}
}
const int N=1e5+5;
long long t,n,m,ans,lcm,mx;
long long hp[N],rh[N],aw[N],st[N],us[N],a[N],p[N];
multiset<long long>ms;
long long mul(long long u,long long v,long long MOD){
long long rep=0;
while(v>0){
if(v&1){
rep=(rep+u)%MOD;
}
u=(u+u)%MOD;
v>>=1;
}
return rep;
}
long long exgcd(long long u,long long v,long long &x,long long &y){
if(v==0){
x=1;y=0;
return u;
}
long long _w=exgcd(v,u%v,y,x);
y-=u/v*x;
return _w;
}
long long x,y;
void excrt(){
ans=a[1];lcm=p[1];
for(int i=2;i<=n;i++){
long long rep=(((a[i]-ans)%p[i])+p[i])%p[i];
long long g=exgcd(lcm,p[i],x,y);
long long pg=p[i]/g;
if(rep%g){
ans=-1;
return;
}
x=mul(x,rep/g,pg);
ans+=lcm*x;
lcm=lcm*pg;
ans=((ans%lcm)+lcm)%lcm;
}
ans=((ans%lcm)+lcm)%lcm;
}
bool check(){
for(int i=1;i<=n;i++){
if(hp[i]>rh[i]){
return 0;
}
}
return 1;
}
int main(){
qread(t);
while(t--){
ans=mx=0;
qread(n);qread(m);
for(int i=1;i<=n;i++){
qread(hp[i]);
}
for(int i=1;i<=n;i++){
qread(rh[i]);
}
for(int i=1;i<=n;i++){
qread(aw[i]);
}
for(int i=1;i<=m;i++){
qread(st[i]);
}
ms.clear();
for(int i=1;i<=m;i++){
ms.insert(st[i]);
}
multiset<long long>::iterator ite;
for(int i=1;i<=n;i++){
ite=ms.upper_bound(hp[i]);
if(ite!=ms.begin()){
--ite;
}
us[i]=*ite;
ms.erase(ite);
ms.insert(aw[i]);
}
for(int i=1;i<=n;i++){
mx=max(mx,(long long)ceil((double)hp[i]/(double)us[i]));
long long g=exgcd(us[i],rh[i],x,y);
p[i]=rh[i]/g;
if(hp[i]%g){
ans=-1;
break;
}
x=((x%p[i])+p[i])%p[i];
a[i]=mul(hp[i]/g,x,p[i]);
}
if(!ans){
if(check()){
excrt();
}
else{
for(int i=1;i<=n;i++){
ans=max(ans,(long long)ceil((double)hp[i]/(double)us[i]));
}
}
}
printf("%lld\n",ans);
}
return 0;
}