1. 程式人生 > 實用技巧 >Luogu P4774 [NOI2018]屠龍勇士

Luogu P4774 [NOI2018]屠龍勇士

題面

題面和資料範圍建議看原題。

題解

注意到每一次打龍的時候選擇的劍都是唯一固定的,而且注意到同一攻擊力的劍可以有多把,所以可以用 multiset 來維護一下。

所以現在打每一條龍相當於一個方程 \(atk_ix+p_iy=a_i\),移項得到 \(atk_ix\equiv a_i\pmod a_i\),直接使用 exCRT 即可。

這裡我的程式碼是邊打龍邊合併方程,其實也可以確定下來劍之後逐一合併方程,long longlong 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();
    }
}