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 }

 

posted @ 2018-07-21 18:57  menhera  阅读(282)  评论(0编辑  收藏  举报