Luogu P4774 [NOI2018]屠龙勇士
题面
题面和数据范围建议看原题。
题解
注意到每一次打龙的时候选择的剑都是唯一固定的,而且注意到同一攻击力的剑可以有多把,所以可以用 multiset
来维护一下。
所以现在打每一条龙相当于一个方程 \(atk_ix+p_iy=a_i\),移项得到 \(atk_ix\equiv a_i\pmod{a_i}\),直接使用 exCRT 即可。
这里我的代码是边打龙边合并方程,其实也可以确定下来剑之后逐一合并方程,long long
乘 long long
可以直接龟速乘。
判断无解的情况比较麻烦,建议对代码看。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll MAXN=1e5+51;
ll test,n,m,xx,yy,kk,mx,c,g;
ll x[MAXN],y[MAXN],p[MAXN];
multiset<ll>st;
multiset<ll>::iterator it;
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void exgcd(ll x,ll y,ll &xx,ll &yy)
{
ll t;
if(!y)
{
return (void)(xx=1,yy=0,g=x);
}
exgcd(y,x%y,xx,yy),t=xx,xx=yy,yy=t-x/y*yy;
}
inline ll mul(ll x,ll y,ll md)
{
ll res=0;
while(y)
{
if(y&1)
{
res=(res+x)%md;
}
x=(x<<1)%md,y>>=1;
}
return res;
}
inline void solve()
{
n=read(),m=read();
for(register int i=1;i<=n;i++)
{
x[i]=read();
}
for(register int i=1;i<=n;i++)
{
p[i]=read();
}
for(register int i=1;i<=n;i++)
{
y[i]=read();
}
st.clear();
for(register int i=1;i<=m;i++)
{
st.insert(read());
}
mx=c=0,m=1;
for(register int i=1;i<=n;i++)
{
it=st.upper_bound(x[i]),it!=st.begin()?--it:it,kk=*it,st.erase(it);
st.insert(y[i]),mx=max(mx,(x[i]-1)/kk+1),kk%=p[i],x[i]%=p[i];
if(!kk&&x[i])
{
return (void)puts("-1");
}
if(!kk&&!x[i])
{
continue;
}
exgcd(kk,p[i],xx,yy);
if(x[i]%g)
{
return (void)puts("-1");
}
p[i]/=g,x[i]=mul(x[i]/g,(xx%p[i]+p[i])%p[i],p[i]),exgcd(m,p[i],xx,yy);
if((x[i]-c)%g)
{
return (void)puts("-1");
}
m=m/g*p[i],c=(c+mul(mul(m/p[i],((x[i]-c)%m+m)%m,m),(xx%m+m)%m,m))%m;
}
printf("%lld\n",c>=mx?c:c+m*((mx-c-1)/m+1));
}
int main()
{
test=read();
for(register int i=0;i<test;i++)
{
solve();
}
}