[NOI2018] 屠龙勇士 题解

Statement

P4774 屠龙勇士 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

一个小提示 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solve1

首先,容易发现,剑的顺序是固定的

我们可以轻松地用 \(multiset\) 处理出面对第 \(i\) 条龙时的攻击力 \(atk[i]\)

那么题目就是求解一堆同余方程组

\[atk[i]\times x\equiv a[i]\pmod{m[i]} \]

其中, \(a[i]\) 是初始生命值,\(m[i]\) 是回复值

这个形式非常像我们的扩展中国定理\(x\equiv a[i]\pmod{m[i]}\)

我们不妨延续 \(\text{exCRT}\) 的思路:

\(ans\) 表示前 \(i-1\) 个方程的解 \(x\)\(M\) 表示 \(lcm_{1\leq j<i}\{m[j]\}\)

知道通解 \(ans=ans+xM\)

那么有 \(atk[i]\times(ans+xM)\equiv a[i]\pmod{m[i]}\)

\(atk[i]\times ans+atk[i]\times xM+ym[i]=a[i]\)

同时减去一个 \(atk[i]\times ans\)\(atk[i]M\times x+m[i]\times y=a[i]-ans\times atk[i]\)

其中 \(atk[i],M,m[i],a[i],ans\) 皆为常数,那不就是标准的 \(\text{exgcd}\) 嘛,

(一下是扩展欧几里得具体过程,可以略过)

\(a=atk[i]M,b=m[i],c=a[i]-ans\times atk[i]\)

\(ax+by=(a,b)\) 的特解 \(x^{\prime} ,y^{\prime}\)

有通解 \(x=\dfrac c{(a,b)}x^{\prime}+k\dfrac b{(a,b)}\)

那么 \(ans+=xM,M^{*}=\dfrac b {(a,b)}\)

特别的\(atk[i]\times x\geq a[i]\) ,即必须砍成负血

\(maxx=max\{\dfrac{a[i]-1}{atk[i]}+1\}\) ,即最多几刀砍成负血

那么,如果我们的 \(ans<maxx\) ,也就是 \(\exist i,s.t. atk[i]\times ans<a[i]\)

我们设还应砍 \(x\times M\) 刀,满足 \(ans+x\times M\geq maxx\)

可知 \(x=\dfrac{maxx-ans-1}{M}+1\) ,加在答案里即可

Code1

#include<bits/stdc++.h>
#define int __int128
using namespace std;
const int N = 1e5+5;

int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
void write(int x){
    vector<long long> v;
    while(x) v.emplace_back(x%10),x/=10;
    for(int i=v.size()-1;~i;--i)printf("%lld",v[i]);
    puts("");
}

int a[N],m[N],gift[N],atk[N];
int T,n,m_,maxx;
multiset<int>s;

int exgcd(int a,int b,int &x,int &y){
    if(!b)return x=1,y=0,a;
    int g=exgcd(b,a%b,y,x);
    return y-=a/b*x,g;
}

void exCRT(){
    int ans=0,M=1,x,y,aa,b,c,g;
    for(int i=1;i<=n;++i){
        aa=atk[i]*M%m[i],b=m[i];
        c=(a[i]-ans*atk[i]%m[i]+m[i])%m[i],g=exgcd(aa,b,x,y);
        if(c%g)return puts("-1"),void();
        x=(x+b)%b,x=(c/g*x)%(b/g);
        ans+=x*M%(M*=b/g);
        ans%=M;
    }
    if(ans<maxx)ans+=((maxx-ans-1)/M+1)*M;
    write(ans);
}

signed main(){
    T=read();
    while(T--){
        s.clear(),maxx=0;
        n=read(),m_=read();
        for(int i=1;i<=n;++i)a[i]=read();
        for(int i=1;i<=n;++i)m[i]=read();
        for(int i=1;i<=n;++i)gift[i]=read();
        for(int i=1,x;i<=m_;++i)x=read(),s.insert(x);
        for(int i=1;i<=n;++i){
            auto u=(a[i]<(*s.begin()))?s.begin():(--s.upper_bound(a[i]));
            atk[i]=*u,s.erase(u),s.insert(gift[i]),maxx=max(maxx,(a[i]-1)/atk[i]+1);
        }
        exCRT();
    }
    return 0;
}

Solve2

参考:题解 P4774 NOI2018 屠龙勇士- shadowice1984 的博客

我们换一种思路考虑如何把 \(atk[i]x\equiv a[i]\pmod{m[i]}\) 直接转化成 \(x \equiv y\pmod{z}\) ,也就是让它们等价。

考虑如何干掉 \(atk[i]\) 这一项

先转成 \(atk[i]x+bm[i]=a[i]\)

不妨求出 \(atk[i]x+bm[i]=(atk[i],m[i])\) 的一个特解 \(x^{\prime}\)

有通解 \(x=\frac{atk[i]}{(atk[i],m[i])}x^{\prime}+k\frac{m[i]}{(atk[i],m[i])}\)

不妨把这个通解转化成同余的形式:

\[x\equiv \frac{atk[i]}{(atk[i],m[i])}x^{\prime}\pmod{\frac{m[i]}{(atk[i],m[i])}} \]

也就是说,只要 \(x\) 满足上述条件,就满足 \(atk[i]x+bm[i]=a[i]\)

也就是说:

\[x\equiv \frac{atk[i]}{(atk[i],m[i])}x^{\prime}\pmod{\frac{m[i]}{(atk[i],m[i])}} \Leftrightarrow atk[i]x\equiv a[i]\pmod{m[i]} \]

于是,我们成功地干掉了 \(atk[i]\) 这一项,之后就可以直接扩展中国剩余定理了。

这里同时给出另外一种扩展中国剩余定理的思路

Solve1 中,采取蓝书《算法竞赛进阶指南》思路,本质是假定前 \(i-1\) 个同余方程等价于:

\[ans\equiv a\pmod M \]

然后考虑如何用 \(ans+tM\) 去兼容第 \(i\) 个方程

另外的一种思路是,考虑合并两个同余方程:

\[\left\{ \begin{aligned} ans&\equiv a&\pmod M\\ c[i]&\equiv a[i]&\pmod {m[i]} \end{aligned} \right. \]

其中的 \(c[i],a[i],m[i]\) 都相应的是经我们前面干掉 \(atk[i]\) 项后的结果

我们可以形式化地转化一下:对于两个同余方程

\[\left\{ \begin{aligned} x\equiv y_1\pmod{p_1} \\ x\equiv y_2\pmod{p_2} \end{aligned} \right. \]

要求转化成 \(X\equiv Y\pmod P\) 的式子

我们直接拆开:\(x=n_1p_1+y_1=n_2p_2+y_2\)

注意到 \(n_1,n_2\) 正负号任意,\(n_1p_1=n_2p_2+y_2-y_1\)

这就是一个二元一次不定方程的形式,有解当且仅当 \((p_1,p_2)|(y_2-y_1)\)

现在我们转化成了 \(n_1p_1\equiv y_2\pmod{p_2}\) ,考虑如何干掉 \(p_1\) 这个系数

最直接的想法就是逆元,但不保证 \(p_1\)\(p_2\) 互质

我们知道 \(gcd\) 有这样一个性质: \((\dfrac a{(a,b)},\dfrac b{(a,b)})=1\)

所以不妨在之前的式子同除 \((p_1,p_2)\) ,得到

\[n_1\frac{p_1}{(p_1,p_2)}=n_2\frac{p_2}{(p_1,p_2)}+\frac{y_2-y_1}{(p_1,p_2)} \]

转化成同余式 :

\[n_1\frac{p_1}{(p_1,p_2)}\equiv\frac{y_2-y_1}{(p_1,p_2)}\pmod{\frac{p_2}{(p_1,p_2)}} \]

此时,我们可以求 \(\frac{p_1}{(p_1,p_2)}\) 在模 \(\frac{p_2}{(p_1,p_2)}\) 意义下的逆元了,设为 \(inv\)

那么:

\[n_1\equiv inv\times\frac{y_2-y_1}{(p_1,p_2)}\pmod{\frac{p_2}{(p_1,p_2)}} \]

写成不定方程的形式:

\[n_1=inv\times\frac{y_2-y_1}{(p_1,p_2)}+k\frac{p_2}{(p_1,p_2)} \]

回顾我们的目标,是转化成 \(X\equiv Y\pmod P\) 的形式

但注意到 \(n_1\) 是这样来的:\(x=n_1p_1+y_1\)

显然 \(n_1\) 依赖于 \(x\) ,有多个解,不利于我们操作

所以我们把 \(n_1\) 带入:

\[x=p_1\times[inv\times\frac{y_2-y_1}{(p_1,p_2)}\% \frac{p_2}{(p_1,p_2)}]+k\frac{p_1p_2}{(p_1,p_2)}+y_1 \]

转化成同余方程:

\[x\equiv p_1\times[inv\times\frac{y_2-y_1}{(p_1,p_2)}\% \frac{p_2}{(p_1,p_2)}]+y_1\pmod{\frac{p_1p_2}{(p_1,p_2)}} \]

合并成功!

Code2

请参见这位大佬

posted @ 2021-09-16 20:39  _Famiglistimo  阅读(73)  评论(0编辑  收藏  举报