传送门
题目大意

输入格式

输出格式

数据范围

样例解释

题解
因为每次巨龙面对的剑是可以确定的
所以设gi表示第i只龙面对的剑的攻击力
容易发现ai−gix≡0(modpi)
移项得gix≡ai(modpi)
也就是x≡ai×gi−1(modpi)
gi−1是gi的逆元
根据模运算的消去律
柿子可以转成酱紫:x≡dai×(dgi)−1(moddpi)
其中d=gcd(ai,gi,pi)
因为pi不一定是素数,所以不能用费马小定理
可以用扩展欧几里得(exgcd)
然鹅dgi与dpi必须互质,否则前者没有逆元,即无解,输出-1
然后我们会得到一堆类似x≡ci(modpi)的柿子
用扩展中国剩余定理两两合并,举个栗子(摘自OI-WiKi)
设两个方程x≡a1(modp1),x≡a2(modp2)
将它们转化成不定方程:x=p1r+a1=p2s+a2,其中r,s是整数,则有p1r−p2s=a2−a1
由裴蜀定理,当a2−a1不能被gcd(m1,m2)整除时,无解,输出-1
其他情况下,可以通过扩展欧几里得算法解出来一组可行解:(p,q)
则原来的两方程组成的模方程组的解为 x≡b(modM),其中b=m1p+a1,M=lcm(m1,m2)
最后得出x≡res(modLCM)
另外,由于两个long long一起乘会炸,所以请使用龟速快速乘
回到前面,如何在O(nlogn)的时间复杂度内找出gi?
可以用线段树,但是——
有现成的multiset,为何放着不用呢?
此处不多介绍,自己上网查找
P.s:不知道是因为我写丑了还是什么原因,跑的贼慢,大佬勿喷
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #pragma GCC optimize(2) #pragma GCC optimize(3) #include <set> #include <cstdio> #define N 1000005 #define ll long long #define int64 long long #define mulit multiset<ll>::iterator using namespace std; ll i,T,n,m,a[N],g[N],p[N],r[N],mx; ll exgcd(ll a,ll b,ll &x,ll &y) { if (!b) return x=1,y=0,a; ll d=exgcd(b,a%b,x,y); ll t=x;x=y,y=t-(a/b)*y; return d; }ll gcd(ll a,ll b) { if (!b) return a; return gcd(b,a%b); }int64 inv(int64 a,int64 b) { int64 x,y;exgcd(a,b,x,y); return x; }int64 mul(ll a,ll b,ll mo,ll res=0,bool f=0) { if (b<0) f=1,b=-b; for (;b;b>>=1,a=(a+a)%mo) { if (b&1) res=(res+a)%mo; }return (f)?-res:res; }int64 excrt(int64 &res) { ll lcm=1;res=0; for (int i=1;i<=n;++i) { ll d1=gcd(a[i],gcd(g[i],p[i])); a[i]/=d1,g[i]/=d1,p[i]/=d1; if (gcd(g[i],p[i])>1) return res=-1,1; ll y=mul(a[i],inv(g[i],p[i]),p[i])+p[i];y%=p[i]; ll c=y-res,r,s,d=gcd(lcm,p[i]); if (c%d) return res=-1,1; exgcd(lcm/d,p[i]/d,r,s); ll t1=mul(c/d,lcm,lcm/d*p[i]); ll t2=mul(t1,r,lcm/d*p[i]); res+=t2,lcm=lcm/d*p[i]; res%=lcm,res+=lcm,res%=lcm; }return lcm; }multiset<int64> h; int main() { scanf("%lld",&T); while (T--) { h.clear(),mx=0;scanf("%lld%lld",&n,&m); for (i=1;i<=n;++i) scanf("%lld",a+i); for (i=1;i<=n;++i) scanf("%lld",p+i); for (i=1;i<=n;++i) scanf("%lld",r+i); for (i=1;i<=m;++i) { ll x;scanf("%lld",&x); h.insert(x); }for (i=1;i<=n;++i) { mulit it=h.upper_bound(a[i]); if (it!=h.begin()) --it; g[i]=*it,h.erase(it); mx=max(mx,(a[i]+g[i]-1)/g[i]); h.insert(r[i]); }int64 x,lcm=excrt(x); if (x!=-1 && x<mx) x+=(mx-x+lcm-1)/lcm; printf("%lld\n",x); } }
|