题意比较麻烦,感觉我来说也简单不了多少,就不说了,直接看原题吧。
题解:
一道题解咕了大半年的题,现在终于来补锅了。当时网上同步赛的时候我是真的菜啊,那时候就写了一些特殊性质的点,甚至连这是一堆同余方程之后求个最小解都没看出来。
感觉这个题前面部分出的没什么意思,就强行拿个multiset来模拟算出每一次该用的是哪一把剑。确定了这个之后,我们来考虑这个回血的过程,我们发现和取模有点像。于是我们就会列出一堆同余方程,形如 a t k i ∗ x = a i ( m o d p i ) atk_i*x=a_i(mod\ p_i) atki∗x=ai(mod pi),然后我们要求出一个满足所有方程的最小 x x x。这个东西没有什么互质的性质,那么我们就去看看能不能用扩展中国剩余定理。但是我们发现另一个问题是,不能直接把 a t k i atk_i atki除过去,因为可能 a t k i atk_i atki与 p i p_i pi不互质,没有逆元。那么我们的做法是先求出他们的gcd,然后这个式子整体除掉这个gcd,这样就能求逆元了。
主要思路和做法就是这个样子,但是问题在于,这个题比较烦人,他还有很多的细节。首先,可能本来的血量 a i a_i ai比 p i p_i pi大,这样你求出来的最小值是不对的,因为你是找到了 a i a_i ai模 p i p_i pi之后的值要多少次,我们还要把它先弄到一个小于 p i p_i pi的值。但是对于这个问题,这个题有一个比较有意思的地方,他的所有测试点要么满足 a i < = p i a_i<=p_i ai<=pi,要么满足 p i = 1 p_i=1 pi=1。那么我们就特判一下, p i = 1 p_i=1 pi=1很好做,就是只要打到血量小于 0 0 0就可以了。于是求法就是每一个的血量除以每次的攻击力上取整,然后取个max就完了。
还要各种奇怪的特例,我有点不想分析了,感觉这个题主要是挺烦的。想看的看我代码吧。
代码:
#include <bits/stdc++.h>
using namespace std;
int T,n,m,pd,ji;
long long a[100010],p[100010],k[100010],b[100010];
multiset <long long> s;
inline long long gcd(long long x,long long y)
{
return y?gcd(y,x%y):x;
}
inline void exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b)
{
x=1;
y=0;
}
else
{
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
inline long long mul(long long x,long long y,long long mod)
{
y%=mod;
if(y<0)
y+=mod;
long long res=0;
while(y)
{
if(y&1)
res=(res+x)%mod;
x=(x<<1)%mod;
y>>=1;
}
return res;
}
inline long long inv(long long a,long long b)
{
long long x,y;
a%=b;
exgcd(a,b,x,y);
x=(x%b+b)%b;
if(!x)
x+=b;
return x;
}
int main()
{
scanf("%d",&T);
multiset<long long>::iterator it;
while(T--)
{
s.clear();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&p[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&b[i]);
for(int i=1;i<=m;++i)
{
long long x;
scanf("%lld",&x);
s.insert(x);
}
pd=0;
ji=0;
for(int i=1;i<=n;++i)
{
it=s.upper_bound(a[i]);
if(it!=s.begin())
--it;
k[i]=*it;
s.erase(it);
s.insert(b[i]);
}
for(int i=1;i<=n;++i)
{
if(p[i]!=1)
ji=1;
}
if(ji==0)
{
long long res=0;
for(int i=1;i<=n;++i)
res=max(res,(a[i]+k[i]-1)/k[i]);
printf("%lld\n",res);
continue;
}
ji=0;
for(int i=1;i<=n;++i)
{
if(p[i]!=a[i])
ji=1;
}
if(ji==0)
{
long long ans=1;
for(int i=1;i<=n;++i)
{
if(p[i]%k[i])
{
pd=1;
printf("-1\n");
break;
}
long long qwq=(p[i]+k[i-1])/k[i];
ans=ans/gcd(ans,qwq)*qwq;
}
if(pd==0)
printf("%lld\n",ans);
continue;
}
for(int i=1;i<=n;++i)
{
k[i]%=p[i];
if(!k[i]&&a[i]==p[i])
{
k[i]=1;
p[i]=1;
a[i]=0;
}
else if(!k[i])
{
printf("-1\n");
pd=1;
break;
}
}
if(pd==1)
continue;
for(int i=1;i<=n;++i)
{
long long g=gcd(k[i],p[i]);
if(a[i]%g)
{
printf("-1\n");
pd=1;
break;
}
if(pd==1)
break;
long long x,y;
exgcd(k[i],p[i],x,y);
p[i]/=g;
x=(x%p[i]+p[i])%p[i];
a[i]=mul(a[i]/g,x,p[i]);
}
if(pd==1)
continue;
for(int i=1;i<=n-1;++i)
{
long long g=gcd(p[i],p[i+1]);
if((a[i+1]-a[i])%g)
{
printf("-1\n");
pd=1;
break;
}
if(pd==1)
break;
long long ji=mul(inv(p[i]/g,p[i+1]/g),(a[i+1]-a[i])/g,p[i+1]/g);
a[i+1]=(mul(ji,p[i],p[i+1]/g*p[i])+a[i])%(p[i+1]/g*p[i]);
p[i+1]=p[i+1]/g*p[i];
}
if(pd==0)
printf("%lld\n",a[n]);
}
return 0;
}