[LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龍勇士

[LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龍勇士

題意

題面好囉嗦啊直接粘LOJ題面好了php

小 D 最近在網上發現了一款小遊戲。遊戲的規則以下:c++

  • 遊戲的目標是按照編號 \(1\)~\(n\) 順序殺掉 \(n\) 條巨龍,每條巨龍擁有一個初始的生命值 \(a_i\) 。同時每條巨龍擁有恢復能力,當其使用恢復能力時,它的生命值就會每次增長 \(p_i\),直至生命值非負。只有在攻擊結束後且當生命值剛好\(0\) 時它纔會死去。
  • 遊戲開始時玩家擁有 \(m\) 把攻擊力已知的劍,每次面對巨龍時,玩家只能選擇一把劍,當殺死巨龍後這把劍就會消失,但做爲獎勵,玩家會得到全新的一把劍。

小 D 以爲這款遊戲十分無聊,但最快通關的玩家能夠得到 ION2018 的參賽資格, 因而小 D 決定寫一個笨笨的機器人幫她通關這款遊戲,她寫的機器人遵循如下規則:測試

  • 每次面對巨龍時,機器人會選擇當前擁有的,攻擊力不高於巨龍初始生命值中攻擊力最大的一把劍做爲武器。若是沒有這樣的劍,則選擇攻擊力最低的一把劍做爲武器。
  • 機器人面對每條巨龍,它都會使用上一步中選擇的劍攻擊巨龍固定的 \(x\) 次,使巨龍的生命值減小 \(x \times ATK\)
  • 以後,巨龍會不斷使用恢復能力,每次恢復 \(p_i\) 生命值。若在使用恢復能力前或某一次恢復後其生命值爲 \(0\),則巨龍死亡,玩家經過本關。

那麼顯然機器人的攻擊次數是決定可否最快通關這款遊戲的關鍵。小 D 如今得知了每條巨龍的全部屬性,她想考考你,你知道應該將機器人的攻擊次數 \(x\) 設置爲多少,才能用最少的攻擊次數通關遊戲嗎?ui

固然若是不管設置成多少都沒法通關遊戲,輸出 \(-1\) 便可。spa

殺龍的時候須要三步必殺, 不能重複屢次qwq...3d

\(n\le 10^5,m\le 10^5,a_i\le 10^{12}\).rest

對於全部的測試點,\(T \le 5\),全部武器的攻擊力 \(\le 10^6\),全部 \(p_i\)最小公倍數 \(\le 10^{12}\)code

題解

乍一看這題神仙的一匹, 然而冷靜分析一下能夠發現:blog

拿來淦龍的劍都是固定的, 並且每次至關於把龍的血打到一個不大於 \(0\)\(p_i\) 的倍數就能夠完成任務了.遊戲

那麼也就是說只要讓 \(x\) 知足:
\[ x\times ATK_i\equiv a_i \pmod {p_i}\\ x\times ATK_i\ge a_i \]
先來搞第一個限制.

不難發現這個限制至關於下式:
\[ x\times ATK_i+k\times p_i=a_i \]
其中 \(ATK_i,p_i,a_i\) 都是肯定的, 顯然這個東西能夠隨手 ExGCD 搞一搞解出一個 \(\bmod p_i\) 意義下的 \(x\).

不過注意這一步要對 \(ATK_i\)\(p_i\) 進行約分, 否則逆元不惟一就會解出奇怪的東西qaq(sb rvalue在這坑了一個小時)...

而後咱們不難發現咱們獲得了一堆形如這樣的方程組:
\[ x\equiv r_i \pmod {p_i} \]
這不裸的 CRT 麼?

然而 \(p_i\) 不互質. 並不能直接 CRT.

考慮 ExCRT. ExCRT 的大致思路是經過 ExGCD 來合併兩個同餘方程.

假設咱們如今有兩個同餘方程:
\[ \begin{cases} x\equiv a &\pmod n\\ x\equiv b &\pmod m \end{cases} \]
不難發現它等價於:
\[ \begin{cases} x = a + pn\\ x = b + qm \end{cases} \]
那麼也就是說:
\[ a+pn=b+qm \]
移項可得:
\[ a-b=qm-pn \]
好了咱們能夠 ExGCD 了.

算出 \(p\)\(q\) 以後能夠用 \(x=a+pn=b+pm\) 算出 \(x\) 來. 它與全部 \(\bmod \gcd(n,m)\) 意義下同餘的值都是這兩個方程的解. 顯然咱們直接對 \(\gcd(n,m)\) 取模就能夠獲得最小值了.

一直這樣合併下去, 只要 ExGCD 的時候出鍋那麼根據Bézout定理這個方程組無解.

而後咱們能夠獲得一個 \(\bmod \operatorname{lcm} \{p_i\}\)\(x\). 接着考慮第二種限制.

顯然咱們能夠對當前已有的 \(x\) 計算它是否知足 \(x\times ATK_i\ge a_i\), 若是不知足的話把 \(x\) 變爲 \(\bmod \operatorname{lcm} \{p_i\}\) 意義下同餘的最小知足條件的值就能夠了. 不難發現答案就是:
\[ x+\operatorname{lcm}\{p_i\}\times \max_{1\le i\le n}\left \lceil \frac {\left \lceil \frac{a_i}{ATK_i}\right \rceil-x}{\operatorname{lcm}\{p_i\}}\right \rceil \]
UOJ由於有Hack因此數據比LOJ強一些, LOJ過了以後建議在UOJ上交一發.

參考代碼

下面這份代碼在發文時沒有被Hack qwq...

#include <bits/stdc++.h>

const int MAXN=1e5+10;
typedef long long intEx;

struct Equation{
    intEx mod;
    intEx rest;
};
Equation E[MAXN];

int n;
int m;
intEx a[MAXN];
intEx p[MAXN];
intEx w[MAXN];
intEx atk[MAXN];

intEx Mul(intEx,intEx,intEx);
intEx ExGCD(intEx,intEx,intEx&,intEx&);

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        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",w+i);
        std::multiset<intEx> s;
        for(int i=1;i<=m;i++){
            intEx x;
            scanf("%lld",&x);
            s.insert(x);
        }
        try{
            for(int i=1;i<=n;i++){
                E[i].mod=p[i];
                auto it=s.upper_bound(a[i]);
                if(it!=s.begin())
                    --it;
                intEx t;
                atk[i]=*it;
                s.erase(it);
                intEx gcd=ExGCD(atk[i],p[i],E[i].rest,t);
                if(a[i]%gcd!=0)
                    throw std::logic_error(R"(a[i]%gcd!=0)");
                E[i].mod/=gcd;
                E[i].rest=Mul(a[i]/gcd,E[i].rest,E[i].mod);
                (E[i].rest+=E[i].mod)%=E[i].mod;
                s.insert(w[i]);
            }
            for(int i=2;i<=n;i++){
                intEx x,y;
                intEx gcd=ExGCD(E[i-1].mod,E[i].mod,x,y);
                intEx lcm=E[i-1].mod/gcd*E[i].mod;
                if((E[i-1].rest-E[i].rest)%gcd!=0)
                    throw std::logic_error(R"((E[i].rest-E[i-1].rest)%gcd!=0 @)"+std::to_string(i));
                intEx scale=(E[i-1].rest-E[i].rest)/gcd;
                (E[i].rest+=Mul(Mul(scale,y,lcm),E[i].mod,lcm))%=lcm;
                E[i].mod=lcm;
                E[i].rest=(E[i].rest+lcm)%lcm;
            }
            intEx scale=0;
            for(int i=1;i<=n;i++)
                scale=std::max(scale,((a[i]+atk[i]-1)/atk[i]-E[n].rest+E[n].mod-1)/E[n].mod);
            printf("%lld\n",E[n].rest+scale*E[n].mod);
        }
        catch(std::logic_error x){
            puts("-1");
            continue;
        }
    }
    return 0;
}

intEx ExGCD(intEx a,intEx b,intEx& x,intEx& y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    intEx gcd=ExGCD(b,a%b,y,x);
    y-=(a/b)*x;
    return gcd;
}

intEx Mul(intEx a,intEx b,intEx p){
    return __int128(a)*b%p;
}

相關文章
相關標籤/搜索