一道简单的(EXCRT)
题目链接
解析
我们愉快地发现,攻击每条龙的剑的攻击力是确定的.
只用一个(Multiset)来维护攻击力即可.
然后,我们可以把这个题目转化一下.
假设打第(i)条龙时攻击力是(t_i)
(t_ixequiv a_i(mod p_i))
所以只要求解这个方程组即可.
等等!
这只能在(a_i<p_i)的情况下成立.
假设(a_i>p_i),那么可能还没把龙的血量打到(0)就已经是(p)的倍数了.
怎么办?
情况变得复杂起来了
然而,我们仔细地看一看表格
发现当(a_i>p_i)时,所有的(p_i)都为(1)
那么只要特判一下就好了.
那么我们只要求解(t_ixequiv a_i(mod p_i))这个方程组.
我们普通的(EXCRT)只能求解(t_i=1)的情况,那么这个该如何处理呢?
很简单,我们列出不定方程(tx+py=a)(为了方便,以后所有的(t_i)等等省略(i))求出(g=gcd(t,p))
然后用(exgcd)求解这个不定方程.当然啦,如果(a
otequiv0(mod g)),那么就输出(-1).
假设这个方程有解,我们求出了一组解(tx,ty)
用一个据说是叫做裴蜀定理的东西求出方程通解(x=tx+kfrac{p}{g})
两边对(frac{p}{g})取模后得(xequiv tx(mod frac{p}{g}))
我们就成功化简了这个式子!
剩下的事情就很简单了,直接把(excrt)的板子套上去即可.
(EXCRT)的讲解戳这里
还有最重要的一点就是——注意龟速乘
代码如下
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#define N (100010)
#define inf (0x7f7f7f7f)
#define rg register int
#define Label puts("NAIVE")
#define GG ({gg=1,print(-1),ent;break;})
#define spa print(' ')
#define ent print('
')
#define rand() (((rand())<<(15))^(rand()))
typedef long double ld;
typedef long long LL;
typedef unsigned long long ull;
using namespace std;
inline char read(){
static const int IN_LEN=1000000;
static char buf[IN_LEN],*s,*t;
return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
}
template<class T>
inline void read(T &x){
static bool iosig;
static char c;
for(iosig=false,c=read();!isdigit(c);c=read()){
if(c=='-')iosig=true;
if(c==-1)return;
}
for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
if(iosig)x=-x;
}
inline char readchar(){
static char c;
for(c=read();!isalpha(c);c=read())
if(c==-1)return 0;
return c;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN],*ooh=obuf;
inline void print(char c) {
if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
*ooh++=c;
}
template<class T>
inline void print(T x){
static int buf[30],cnt;
if(x==0)print('0');
else{
if(x<0)print('-'),x=-x;
for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
while(cnt)print((char)buf[cnt--]);
}
}
inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
multiset<LL>S;
set<LL>::iterator it;
int T,n,m;
LL c[N],a[N],p[N],rew[N];
LL gcd(LL a,LL b){
if(!b)return a;
return gcd(b,a%b);
}
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b){x=1,y=0;return;}
exgcd(b,a%b,y,x),y-=(a/b)*x;
}
LL mult(LL a,LL b,LL mod){
LL res=0,fu=1;
if(a<0)fu=-fu,a=-a;
if(b<0)fu=-fu,b=-b;
while(b){
if(b&1)res=(res+a)%mod;
a=(a+a)%mod,b>>=1;
}
res*=fu;
if(res<0)(res+=((-res-1)/mod+1)*mod);
return res;
}
LL inv(LL a,LL b){
LL x,y;
exgcd(a,b,x,y);
return (x<=0)?(x+b):x;
}
bool spj(){
for(int i=1;i<=n;i++)
if(p[i]>1)return 0;
LL x=0;
for(int i=2;i<=n;i++)
x=max(x,(c[i]-1)/a[i]+1);
print(x),ent;
return 1;
}
int main(){
read(T);
while(T--){
bool gg=0;
read(n),read(m),S.clear();
for(int i=1;i<=n;i++)read(c[i]);
for(int i=1;i<=n;i++)read(p[i]);
for(int i=1;i<=n;i++)read(rew[i]);
for(int i=1;i<=m;i++){
LL x;
read(x),S.insert(x);
}
for(int i=1;i<=n;i++){
it=S.upper_bound(c[i]);
if(it==S.begin())a[i]=*it;
else it--,a[i]=*it;
S.erase(it),S.insert(rew[i]);
}
if(spj())continue;
for(int i=1;i<=n;i++)a[i]%=p[i];
for(int i=1;i<=n;i++)
if(a[i]==0){
if(p[i]==c[i])
a[i]=1,p[i]=1,c[i]=0;
else GG;
}
if(gg)continue;
for(int i=1;i<=n;i++){
LL A=a[i],C=c[i],P=p[i];
LL g=gcd(A,P);if(C%g!=0)GG;
LL tx,ty; exgcd(A,P,tx,ty);
P/=g,tx=(tx%P+P)%P,C=mult(tx,C/g,P);
a[i]=A,c[i]=C,p[i]=P;
}
if(gg)continue;
LL c1=c[1],p1=p[1];
for(int i=2;i<=n;i++){
LL mo=p[i],c2=c[i];
LL t=gcd(p1,mo),s=inv(p1/t,mo/t),tc=c1,tm=p1;
if((c2-c1)%t!=0)GG;
p1=(mo/t*tm),c1=(tc+mult(tm,mult(s,(c2-c1)/t,(mo/t)),p1))%p1;
}
if(gg)continue;
if(c1<0)c1+=((-c1-1)/p1+1)*p1;
print(c1%p1),ent;
}
return flush(),0;
}