[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 }

 

posted @ 2018-07-25 20:16  HocRiser  阅读(316)  评论(0编辑  收藏  举报