NOI2018:屠龙勇士
具体思路:发现对于每条巨龙,用的剑是一样的,那么可以用map先处理出来
然后对于每个龙就是一个一次同余方程,然后n条龙就是一个方程组,那么就是个CRT了
由于可能爆long long,要用龟速快速乘(考试时没想到结果爆成暴力分)
AC代码
#include<bits/stdc++.h> using namespace std; #define int long long const int N=100010; int T,n,m,a[N],p[N],atk[N],be[N],each[N],x,y,re[N],mod[N]; map<int,int> mp; map<int,int>::iterator it; int Mul(int a,int b,int md) { int res=0;a=(a%md+md)%md,b=(b%md+md)%md; while(b) { if(b&1)res=(res+a)%md; b>>=1,a<<=1,a%=md; } return res; } inline int gcd(int a,int b){return b?gcd(b,a%b):a;} int ex_gcd(int a,int b,int &x,int &y) { int d=a; if(!b)x=1,y=0;else d=ex_gcd(b,a%b,y,x),y-=(a/b)*x; return d; } int MLE(int *r,int *mod,int n) { int lm=0,lb=1; for (int i=0;i<n;i++) { int k1,k2; int d=ex_gcd(lb, mod[i],k1,k2); if ((lm-r[i])%d)return -1; lb=lb/d*mod[i]; int z=Mul(k2,((lm-r[i])/d),lb); lm=Mul(z,mod[i],lb)+r[i],lm=((lm%lb)+lb)%lb; } if(lm)return lm;else return lb; } signed main() { scanf("%lld",&T); while(T--) { scanf("%lld%lld",&n,&m);mp.clear();int onlyone=1; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)scanf("%lld",&p[i]),onlyone&=p[i]==1; for(int i=1;i<=n;i++)scanf("%lld",&atk[i]); for(int i=1;i<=m;i++)scanf("%lld",&be[i]),mp[be[i]]++; for(int i=1;i<=n;i++) { it=mp.begin(); if((*it).first>a[i]) { (*it).second--;each[i]=(*it).first; if((*it).second==0)mp.erase(it); }else { it=mp.upper_bound(a[i]);it--; (*it).second--;each[i]=(*it).first; if((*it).second==0)mp.erase(it); } mp[atk[i]]++; } int ans=1; if(onlyone) { ans=0; for(int i=1;i<=n;i++)ans=max(ans,(a[i]/each[i])+((a[i]%each[i])>0)); printf("%lld\n",ans);continue; } for(int i=1;i<=n;i++) { int g=gcd(each[i],p[i]); each[i]/=g,p[i]/=g; if(a[i]%g){ans=0;break;} a[i]/=g; ex_gcd(each[i],p[i],x,y);int inv=x; re[i]=Mul(inv,a[i],p[i]);mod[i]=p[i];if(mod[i]==1)re[i]=1; } if(ans==0){puts("-1");continue;} ans=MLE(re+1,mod+1,n); printf("%lld\n",ans); } return 0; }