到现在我才知道upper_bound和lower_bound的区别。。。
如果为升序,lower_bound指的是大于等于x的数,而upper_bound指的是大于x的数。
同理为降序,lower_bound指的是小于等于x的数,而upper_bound指的是小于x的数。
再来介绍一下拓展中国剩余定理。
本蒟蒻的证明。。。若有问题请大家提出。。https://blog.csdn.net/zzk_233/article/details/82901942
对于剑的攻击力需要先用拓展gcd求出逆元乘到右边,之后就是模板。。当然还有一些特殊情况在代码中说明了。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
typedef long long ll;
ll x,y,ans,M,maxn,k;
int n,m;
multiset<ll>v;
ll c[100005];
ll p[100005];
ll v1[100005];
ll ex_gcd(ll a,ll b)
{
if(b==0)
{
x=1,y=0;
return a;
}
ll r=ex_gcd(b,a%b);
ll t=x;
x=y;
y=t-a/b*x;
return r;
}
ll mul(ll a,ll b,ll mode)
{
ll s=0;
while(b)
{
if(b%2==1)
{
s=(s+a)%mode;
}
a=(a+a)%mode;
b=b/2;
}
return s;
}
int flag;
int main()
{
int T;
scanf("%d",&T);
multiset<ll>::iterator ty;
while(T--)
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%lld",&c[i]);
}
for(int i = 1;i <= n;i++)
{
scanf("%lld",&p[i]);
}
for(int i = 1;i <= n;i++)
{
scanf("%lld",&v1[i]);
}
v.clear();
for(int i = 1;i <= m;i++)
{
ll x;
scanf("%lld",&x);
v.insert(x);
}
maxn=0,ans=0,M=1,k;
for(int i = 1;i <= n;i++)
{
ty=v.upper_bound(c[i]);
if(ty!=v.begin())ty--;
k=*ty;
v.erase(ty);
v.insert(v1[i]);
maxn=max(maxn,(c[i]-1)/k+1);
k%=p[i];c[i]%=p[i];
if(!k&&c[i])//攻击力整除血量但是回血不整除,显然无解
{
printf("-1\n");
flag=1;
break;
}
if(!k&&!c[i])//攻击力整除血量而且回血也整除,显然一定有解
{
continue;
}
ll gg=ex_gcd(k,p[i]);
if(c[i]%gg)
{
printf("-1\n");
flag=1;
break;
}
p[i]/=gg;c[i]/=gg;k/=gg;
x=(x%p[i]+p[i])%p[i];
c[i]=mul(c[i],x,p[i]);
gg=ex_gcd(M,p[i]);
if((c[i]-ans)%gg)
{
printf("-1\n");
flag=1;
break;
}
M/=gg;M*=p[i];
x=(x%M+M)%M;
ans+=mul(mul(M/p[i],((c[i]-ans)%M+M)%M,M),x,M)%M;
}
if(flag==1)
{
flag=0;
continue;
}
printf("%lld\n",ans>=maxn?ans:maxn);
}
return 0;
}