LOJ2721 [NOI2018] 屠龙勇士 【扩展中国剩余定理】
好久没写了,写一篇凑个数。
题目分析:
这题不难想,讲一下中国剩余定理怎么扩展。
考虑$$\left\{\begin{matrix}x \equiv a\pmod{b}\\ x \equiv c\pmod{d}\end{matrix}\right.$$
不难发现需要满足$gcd(b,d)|(c-a)$才有解。
结合后的模数一定是$lcm(b,d)$。然后扩展gcd合并就行了。
中间过程会超过$10^18$,需要快速乘。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 120000; 5 6 int n,m; 7 long long a[maxn],p[maxn],LP[maxn],d[maxn]; 8 9 multiset<long long,greater<long long> > s; 10 11 long long cut[maxn],minn; 12 long long st[maxn],f[maxn]; 13 14 void init(){ 15 s.clear();memset(st,0,sizeof(st)); memset(f,0,sizeof(f)); 16 for(int i=1;i<=m;i++) s.insert(d[i]); 17 for(int i=1;i<=n;i++){ 18 set<long long>::iterator it = s.lower_bound(a[i]); 19 if(it == s.end())it--; cut[i] = (*it); 20 s.erase(it); s.insert(LP[i]); 21 } 22 minn = 0; 23 for(int i=1;i<=n;i++) minn = max(minn,(long long)ceil((double)a[i]/cut[i])); 24 } 25 26 long long exgcd(long long alpha,long long beta,long long &x,long long &y){ 27 if(beta == 0){x = 1; y = 0; return alpha;} 28 else{ 29 long long res = exgcd(beta,alpha%beta,y,x); 30 y-=x*(alpha/beta); 31 return res; 32 } 33 } 34 35 void read(){ 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 38 for(int i=1;i<=n;i++) scanf("%lld",&p[i]); 39 for(int i=1;i<=n;i++) scanf("%lld",&LP[i]); 40 for(int i=1;i<=m;i++) scanf("%lld",&d[i]); 41 } 42 43 long long multi(long long alpha,long long beta,long long mod){ 44 long long dt,bit = 1,ans = 0; 45 alpha %= mod; beta %= mod; 46 alpha += mod; beta += mod; 47 alpha %= mod; beta %= mod; 48 dt = alpha; 49 while(bit <= beta){ 50 if(bit & beta){ans += dt; if(ans >= mod) ans -= mod;} 51 bit<<=1;dt = (dt+dt); if(dt >= mod) dt -= mod; 52 } 53 return ans; 54 } 55 56 int cntt = 0; 57 void work(){ 58 for(int i=1;i<=n;i++){ 59 long long hd = exgcd(cut[i],p[i],st[i],f[i]); 60 if(a[i] % hd != 0){puts("-1");return;} 61 f[i] = p[i]/hd; st[i] %= f[i]; if(st[i] < 0) st[i] += f[i]; 62 st[i] = multi(st[i],a[i]/hd,f[i]); st[i] %= f[i]; 63 } 64 for(int i=2;i<=n;i++){ 65 long long im = exgcd(f[i],f[i-1],f[0],f[0]); 66 if((st[i]-st[i-1])%im){ 67 puts("-1");return; 68 } 69 long long um = f[i]/im*f[i-1]; 70 long long tf=0; exgcd(f[i-1],f[i],tf,f[0]); 71 tf =multi(tf,(st[i]-st[i-1])/im,um); 72 tf += (-tf/f[i])*f[i]; tf += f[i]; 73 tf = (st[i-1]+multi(tf,f[i-1],um))%um; 74 if(tf < 0) tf += um; 75 f[i] = um; st[i] = tf; 76 } 77 if(st[n] < minn){ 78 st[n] += (minn-st[n])/f[n]*f[n]; 79 } 80 printf("%lld\n",st[n]); 81 //fast multi 82 } 83 84 int main(){ 85 int Tmp; scanf("%d",&Tmp); 86 while(Tmp--){ 87 cntt++; 88 read(); 89 init(); 90 work(); 91 } 92 return 0; 93 }