題解 P4774 【[NOI2018]屠龍勇士】
阿新 • • 發佈:2020-09-11
轉載註明來源:https://www.cnblogs.com/syc233/p/13654606.html
首先發現對每條龍使用的劍是固定的,於是可以用multiset預處理出對每條龍使用的劍 \(b_i\) 。
然後發現題其實是要求一堆形如這個的式子:
\[a_i-x \cdot b_i+y \cdot p_i=0 \ (x,y \in \Z) \]
明顯這是一個二元一次不定方程,把它化成標準形式:
\[x \cdot b_i+y \cdot p_i=a_i \ (x,y \in \Z) \]
用exgcd求出這個方程的一組通解 \(x_0,y_0\) 。若無解,則直接輸出 \(-1\) ,否則有(為了方便,以下均使用 \((i,j)\)
\[x=\frac{a_i}{(b_i,p_i)}x_0+k \cdot \frac{p_i}{(b_i,p_i)} \iff x \equiv x_0 \ ({\rm{mod}} \ \frac{p_i}{(b_i,p_i)}) \]
對每一個二元一次不定方程進行上述操作,令 \(A_i=x_0,B_i=\frac{p_i}{(b_i,p_i)}\) ,則需要求解如下同餘方程組:
\[\begin{cases} x \equiv A_1 \ ({\rm{mod}} \ B_1)\\ x \equiv A_2 \ ({\rm{mod}} \ B_2)\\ \cdots \\ x \equiv A_n \ ({\rm{mod}} \ B_n)\\ \end{cases} \]
用exCRT合併即可。
特判 \(p_i=1\) ,讓所有龍的血量非正即可。
\(\text{Code}:\)
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <set> #define maxn 100005 #define Rint register int #define INF 0x3f3f3f3f using namespace std; typedef long long lxl; template <typename T> inline void read(T &x) { x=0;T f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } inline lxl fti(lxl a,lxl b,lxl mod) { lxl res=0; while(b>0) { if(b&1) (res+=a)%=mod; (a+=a)%=mod; b>>=1; } return res; } inline lxl exgcd(lxl a,lxl b,lxl &x,lxl &y) { if(!b) {x=1,y=0;return a;} lxl res=exgcd(b,a%b,x,y); lxl z=x;x=y;y=z-(a/b)*y; return res; } int n,m; lxl a[maxn],p[maxn],b[maxn],aw[maxn]; multiset<lxl> s; #define IT multiset<lxl>::iterator lxl A[maxn],B[maxn]; int main() { // freopen("P4774.in","r",stdin); int T;read(T); while(T--) { read(n),read(m); s.clear(); lxl mx=0; for(int i=1;i<=n;++i) read(a[i]); for(int i=1;i<=n;++i) read(p[i]),mx=max(mx,p[i]); for(int i=1;i<=n;++i) read(aw[i]); for(int i=1;i<=m;++i) { lxl w;read(w); s.insert(w); } bool flag=true; for(int i=1;i<=n;++i) { IT it=s.upper_bound(a[i]); if(it!=s.begin()) --it; b[i]=*it; s.erase(it); s.insert(aw[i]); lxl x,y,d=exgcd(b[i],p[i],x,y); if(a[i]%d) {flag=false;break;} a[i]/=d,p[i]/=d; x=fti(x,a[i],p[i]); B[i]=p[i]; A[i]=(x%B[i]+B[i])%B[i]; } if(!flag) {puts("-1");continue;} if(mx==1) { lxl ans=0; for(int i=1;i<=n;++i) ans=max(ans,(a[i]+b[i]-1)/b[i]); printf("%lld\n", ans); continue; } lxl M=B[1],ans=A[1]; for(int i=2;i<=n;++i) { lxl b1=M,b2=B[i],c=(A[i]-ans%b2+b2)%b2,x,y; lxl d=exgcd(b1,b2,x,y); if(c%d) {flag=false;break;} b2/=d,c/=d; x=fti(x,c,b2); ans+=M*x; M*=B[i]/d; (ans+=M)%=M; } if(!flag) {puts("-1");continue;} printf("%lld\n",(ans+M)%M); } return 0; }
參考資料:
其實是忘完了去複習了一下