Luogu P4774 [NOI2018]屠龍勇士
阿新 • • 發佈:2020-08-12
題面
題面和資料範圍建議看原題。
題解
注意到每一次打龍的時候選擇的劍都是唯一固定的,而且注意到同一攻擊力的劍可以有多把,所以可以用 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(); } }