[NOI2018]屠龙勇士(exCRT)
首先很明显剑的选择是唯一的,直接用multiset即可。
接下来可以发现每条龙都是一个模线性方程。设攻击第i条龙的剑的攻击力为$s_i$,则$s_ix\equiv a_i\ (mod\ p_i)$。
现在需要将方程化成$x\equiv c_i\ (mod\ m_i)$的形式,从而使用exCRT解决。
变式:$s_ix+p_iy=a_i$,先同除以$gcd(s_i,p_i)$,再使用exgcd解不定方程,求x的最小正整数解。
注意判无解,exCRT结束之后注意要使$x\geqslant max(\frac{a_i}{s_i})$
1 #include<set> 2 #include<cstdio> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 typedef long long ll; 6 using namespace std; 7 8 const int N=100010; 9 multiset<ll>S; 10 bool mark; 11 int n,k,T; 12 ll mx,a[N],p[N],more[N],s[N],c[N],m[N]; 13 14 ll gcd(ll a,ll b){ return b ? gcd(b,a%b) : a; } 15 16 ll mul(ll a,ll b,ll mod){ 17 ll res=0; a%=mod; b%=mod; 18 for (; b; a=(a<<1)%mod,b>>=1) 19 if (b & 1) res=(res+a)%mod; 20 return res; 21 } 22 23 void exgcd(ll a,ll b,ll &x,ll &y){ 24 if (!b){ x=1; y=0; return; } 25 exgcd(b,a%b,y,x); y-=(a/b)*x; 26 } 27 28 ll inv(ll a,ll b){ ll x,y; exgcd(a,b,x,y); x=(x%b+b)%b; return x; } 29 30 bool merge(ll c1,ll c2,ll m1,ll m2,ll &c3,ll &m3){ 31 ll d=gcd(m1,m2); m3=m1/d*m2; 32 if (c2<c1) swap(c1,c2),swap(m1,m2); 33 if ((c2-c1)%d) return 0; 34 c3=(mul(mul(inv(m1/d,m2/d),(c2-c1)/d,m2/d),m1,m3)+c1)%m3; 35 return 1; 36 } 37 38 void work(){ 39 scanf("%d%d",&n,&k); mark=1; mx=0; S.clear(); 40 rep(i,1,n) scanf("%lld",&a[i]); 41 rep(i,1,n) scanf("%lld",&p[i]); 42 rep(i,1,n) scanf("%lld",&more[i]); 43 rep(i,1,k) scanf("%lld",&s[i]),S.insert(s[i]); 44 rep(i,1,n){ 45 multiset<ll>::iterator it=S.upper_bound(a[i]); 46 if (it!=S.begin()) it--; 47 ll s=*it; S.erase(it); S.insert(more[i]); 48 mx=max(mx,(a[i]-1)/s+1); 49 ll d=gcd(s,p[i]); 50 if (a[i]%d) { mark=0; break; } 51 m[i]=p[i]/d; c[i]=mul(inv(s/d,m[i]),a[i]/d,m[i]); 52 } 53 if (!mark) { puts("-1"); return; } 54 rep(i,2,n) if (!merge(c[i-1],c[i],m[i-1],m[i],c[i],m[i])) { mark=0; break; } 55 if (!mark) { puts("-1"); return; } 56 if (c[n]<mx) c[n]+=((mx-c[n]-1)/m[n]+1)*m[n]; 57 printf("%lld\n",c[n]); 58 } 59 60 int main(){ 61 freopen("dragon.in","r",stdin); 62 freopen("dragon.out","w",stdout); 63 for (scanf("%d",&T); T--; ) work(); 64 return 0; 65 }