LG P4774 [NOI2018]屠龙勇士

Description

小 D 最近在网上发现了一款小游戏。游戏的规则如下:

- 游戏的目标是按照编号 $1 \rightarrow n$ 顺序杀掉 $n$ 条巨龙,每条巨龙拥有一个初始的生命值 $a_i$ 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 $p_i$ ,直至生命值非负。只有在攻击结束后且当生命值 **恰好** 为 $0$ 时它才会死去。
- 游戏开始时玩家拥有 $m$ 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。

小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格,于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:

- 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择 **攻击力最低** 的一把剑作为武器。
- 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 $x$ 次,使巨龙的生命值减少 $x \times 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$的线性方程组:

$$\begin{cases}x\equiv c_1(\mod m_1)\\x\equiv c_2(\mod m_2)\end{cases}$$

先转化为一般方程:

$$\begin{cases}x=c_1+m_1x_1\\x=c_2+m_2x_2\end{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(t\in Z)$

将通解代回一式得

$$x\equiv c_1+\frac{m_1(c_2-c_1)}gx'(\mod {\frac{m_1m_2}gt})$$

现在考虑解形如$kx \equiv a \pmod p$的方程组,设总方程为$x\equiv c \pmod m$

设$g=gcd(k,p)$,用Exgcd解$x'$,得$x\equiv\frac a gx'(\mod\frac p g)$

变成了上一个问题

需要的特判:

当$p\mid k$且$p\mid a$,方程恒成立,不与原方程合并

当$p\mid k$且$p\nmid a$,方程恒不成立,判断无解

解方程时不满足裴蜀定理,判断无解

答案需要满足$x\geq\lceil\frac a k\rceil$

#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\n",c>=maxx?c:c+m*((maxx-c-1)/m+1));
    }
    return 0;
}
[NOI2018]屠龙勇士

 

posted @ 2020-12-21 09:00  QDK_Storm  阅读(85)  评论(0编辑  收藏  举报