1. 程式人生 > 其它 >【題解】[NOI2018] 屠龍勇士

【題解】[NOI2018] 屠龍勇士

[NOI2018] 屠龍勇士

\(\text{Solution:}\)

確實是送分題……但細節也確實多……找個好板子很重要

容易得出來就是求一堆形如 \(vx\equiv a_i(\bmod p_i)\) 的方程組,但有很多細節:

首先是,這沒有保證模數互質,所以需要擴充套件中國剩餘定理

其次,模數很大,需要快速乘

inline int QMul(int a,int b,int p){
    a%=p;b%=p;
    int c=(long double)a*b/p;
    int x=a*b,y=c*p;
    int res=(int)(x%p)-(int)(y%p);
    if(res<0)res+=p;return res;
}

還有,取模一定要處理好,原本的程式碼找了好久不知道為什麼判錯了,打算換一個板子背了

要求的解並不是最小整數解,還需要滿足使得 \(vx\gep a_i\)

找後繼的時候如果用 multiset 一定用 \(s.lower_bound\) 而不是其他的,用迭代器那個複雜度是 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n,m,b[N],t[N];
typedef long long ll;
ll a[N],p[N],mx;
multiset<ll>s;
inline int Max(int x,int y){return x>y?x:y;}
void Exgcd(ll a,ll b,ll &x,ll &y,ll &d){
	if(!b){x=1,y=0;d=a;}
	else Exgcd(b,a%b,y,x,d),y-=(a/b)*x;
} 
ll ExCRT(){
	ll ans=0,lcm=1,A,B,C,G,x,y;
	for(int i=1;i<=n;++i){
		A=(__int128)b[i]*lcm%p[i];
		B=p[i],C=(a[i]-b[i]*ans%p[i]+p[i])%p[i];
		Exgcd(A,B,x,y,G);x=(x%p[i]+p[i]%p[i]);
		if(C%G)return -1;
		ans+=(__int128)(C/G)*x%(B/G)*lcm%(lcm*=B/G);
		ans%=lcm;
	}
	if(ans<mx)ans+=((mx-ans-1)/lcm+1)*lcm;
	return ans;
}
int main(){
	cin>>T;
	while(T--){
		s.clear();
		cin>>n>>m;mx=0;
		for(int i=1;i<=n;++i)cin>>a[i];
		for(int i=1;i<=n;++i)cin>>p[i];
		for(int i=1;i<=n;++i)cin>>t[i];
		for(int i=1;i<=m;++i){
			int x;cin>>x;
			s.insert(x);
		}
		for(int i=1;i<=n;++i){
			auto u=s.upper_bound(a[i]);
			if(u!=s.begin())--u;
			b[i]=*u;s.erase(u);s.insert(t[i]);
			mx=Max(mx,(a[i]-1)/b[i]+1);
		}
		printf("%lld\n",ExCRT());
	}
	return 0;
}