Description
小 D 最近在网上发现了一款小游戏。游戏的规则如下:
- 游戏的目标是按照编号 $1
ightarrow n$ 顺序杀掉 $n$ 条巨龙,每条巨龙拥有一个初始的生命值 $a_i$ 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 $p_i$ ,直至生命值非负。只有在攻击结束后且当生命值 **恰好** 为 $0$ 时它才会死去。
- 游戏开始时玩家拥有 $m$ 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。
小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格,于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:
- 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择 **攻击力最低** 的一把剑作为武器。
- 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 $x$ 次,使巨龙的生命值减少 $x imes ATK$ 。
- 之后,巨龙会不断使用恢复能力,每次恢复 $p_i$ 生命值。若在使用恢复能力前或某一次恢复后其生命值为 $0$ ,则巨龙死亡,玩家通过本关。
那么显然机器人的攻击次数是决定能否最快通关这款游戏的关键。小 D 现在得知了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数 $x$ 设置为多少,才能用最少的攻击次数通关游戏吗?
当然如果无论设置成多少都无法通关游戏,输出 $-1$ 即可。
Solution
对于每一条龙的攻击力是已知的,可以用平衡树维护
设当前这一条龙对应的剑攻击力为$k$,攻击次数为$x$,那么必须满足:
$$kx equiv a pmod p 且 kx geq a$$
那么就是解形如$kx equiv a pmod p$的线性方程组
考虑一个其他问题:解形如$x equiv c$的线性方程组:
$$egin{cases}xequiv c_1(mod m_1)\xequiv c_2(mod m_2)end{cases}$$
先转化为一般方程:
$$egin{cases}x=c_1+m_1x_1\x=c_2+m_2x_2end{cases}$$
两式相等:
$$m_1x_1+m_2x_2=c_2-c_1$$
用Exgcd求$x_1$的一个解$x'$,$g=gcd(m_1,m_2)$,通解$frac{c_2-c_1}gx'+frac{m_2}gt(tin Z)$
将通解代回一式得
$$xequiv c_1+frac{m_1(c_2-c_1)}gx'(mod {frac{m_1m_2}gt})$$
现在考虑解形如$kx equiv a pmod p$的方程组,设总方程为$xequiv c pmod m$
设$g=gcd(k,p)$,用Exgcd解$x'$,得$xequivfrac a gx'(modfrac p g)$
变成了上一个问题
需要的特判:
当$pmid k$且$pmid a$,方程恒成立,不与原方程合并
当$pmid k$且$p mid a$,方程恒不成立,判断无解
解方程时不满足裴蜀定理,判断无解
答案需要满足$xgeqlceilfrac a k ceil$
#include<iostream> #include<cstdio> #include<cmath> #include<set> using namespace std; long long T,n,m,a[100005],p[100005],b[100005],maxx,c,G,x,y; multiset<long long>s; inline long long read() { long long w=0,f=1; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return w*f; } void exgcd(long long a,long long b) { if(!b) { G=a,x=1,y=0;return; } exgcd(b,a%b); int t=x; x=y,y=t-a/b*y; } long long mul(long long a,long long k,long long mod) { long long ret=0; while(k) { if(k&1) (ret+=a)%=mod; (a<<=1)%=mod,k>>=1; } return ret; } int main() { T=read(); loop:for(;T;T--) { n=read(),m=read(),s.clear(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) p[i]=read(); for(int i=1;i<=n;i++) b[i]=read(); for(int i=1;i<=m;i++) s.insert(read()); m=1,maxx=c=0; for(int i=1;i<=n;i++) { set<long long>::iterator it=s.upper_bound(a[i]); if(it!=s.begin()) --it; long long k=*it; s.erase(it),s.insert(b[i]),maxx=max(1.0*maxx,ceil((double)a[i]/(double)k)); k%=p[i],a[i]%=p[i]; if(!k&&a[i]) { puts("-1"),T--;goto loop; } if(!k&&!a[i]) continue; exgcd(k,p[i]); if(a[i]%G) { puts("-1"),T--;goto loop; } p[i]/=G,a[i]=mul(a[i]/G,(x%p[i]+p[i])%p[i],p[i]); exgcd(m,p[i]); if((a[i]-c)%G) { puts("-1"),T--;goto loop; } m=m/G*p[i],(c+=mul(mul(m/p[i],((a[i]-c)%m+m)%m,m),(x%m+m)%m,m))%=m; } printf("%lld ",c>=maxx?c:c+m*((maxx-c-1)/m+1)); } return 0; }