1. 程式人生 > >uoj396 [NOI2018]屠龍勇士

uoj396 [NOI2018]屠龍勇士

tor turn multi 又能 方法 clear 次數 通關 [1]

[NOI2018]屠龍勇士

描述

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

遊戲的目標是按照編號 1~n 順序殺掉 n 條巨龍,每條巨龍擁有一個初始的生命值 ai 。同時每條巨龍擁有恢復能力,當其使用恢復能力時,它的生命值就會每次增加 pi,直至生命值非負。只有在攻擊結束後且當生命值恰好為 0 時它才會死去。
遊戲開始時玩家擁有 m 把攻擊力已知的劍,每次面對巨龍時,玩家只能選擇一把劍,當殺死巨龍後這把劍就會消失,但作為獎勵,玩家會獲得全新的一把劍。
小 D 覺得這款遊戲十分無聊,但最快通關的玩家可以獲得 ION2018 的參賽資格, 於是小 D 決定寫一個笨笨的機器人幫她通關這款遊戲,她寫的機器人遵循以下規則:

每次面對巨龍時,機器人會選擇當前擁有的,攻擊力不高於巨龍初始生命值中攻擊力最大的一把劍作為武器。如果沒有這樣的劍,則選擇攻擊力最低的一把劍作為武器。
機器人面對每條巨龍,它都會使用上一步中選擇的劍攻擊巨龍固定的 x 次,使巨龍的生命值減少 x×ATK。
之後,巨龍會不斷使用恢復能力,每次恢復 pi 生命值。若在使用恢復能力前或某一次恢復後其生命值為 0,則巨龍死亡,玩家通過本關。
那麽顯然機器人的攻擊次數是決定能否最快通關這款遊戲的關鍵。小 D 現在得知了每條巨龍的所有屬性,她想考考你,你知道應該將機器人的攻擊次數 x 設置為多少,才能用最少的攻擊次數通關遊戲嗎?

當然如果無論設置成多少都無法通關遊戲,輸出 ?1 即可。

輸入格式

從標準輸入讀入數據。

第一行一個整數 T,代表數據組數。

接下來 T 組數據,每組數據包含 5 行。

每組數據的第一行包含兩個整數,n 和 m,代表巨龍的數量和初始劍的數量;
接下來一行包含 n 個正整數,第 i 個數表示第 i 條巨龍的初始生命值 ai;
接下來一行包含 n 個正整數,第 i 個數表示第 i 條巨龍的恢復能力 pi;
接下來一行包含 n 個正整數,第 i 個數表示殺死第 i 條巨龍後獎勵的劍的攻擊力;
接下來一行包含 m 個正整數,表示初始擁有的 m 把劍的攻擊力。

輸出格式

輸出到標準輸出中。

一共 T 行。

第 i 行一個整數,表示對於第 i 組數據,能夠使得機器人通關遊戲的最小攻擊次數 x,如果答案不存在,輸出 ?1。

樣例一

input
2
3 3
3 5 7
4 6 10
7 3 9
1 9 1000
3 2
3 5 6
4 8 7
1 1 1
1 1

output

59
-1

explanation

第一組數據:

開始時擁有的劍的攻擊力為 {1,9,1000},第 1 條龍生命值為 3,故選擇攻擊力為 1 的劍,攻擊 59 次,造成 59 點傷害,此時龍的生命值為 ?56,恢復 14 次後生命值恰好為 0,死亡。
攻擊力為 1 的劍消失,拾取一把攻擊力為 7 的劍,此時擁有的劍的攻擊力為 {7,9,1000},第 2 條龍生命值為 5,故選擇攻擊力為 7 的劍,攻擊 59 次,造成 413 點傷害,此時龍的生命值為 ?408,恢復 68 次後生命值恰好為 0,死亡。
此時擁有的劍的攻擊力為 {3,9,1000},第 3 條龍生命值為 7,故選擇攻擊力為 3 的劍,攻擊 59 次,造成 177 點傷害,此時龍的生命值為 ?170,恢復 17 次後生命值恰好為 0,死亡。
沒有比 59 次更少的通關方法,故答案為 59。
第二組數據:

不存在既能殺死第一條龍又能殺死第二條龍的方法,故無法通關,輸出 ?1。




excrt 板子題,就是看你細不細心,註意要乘爆longlong, 所以要做快速乘QAQ。。。


#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct lpl{
    long long atk, ai, pi, data;
}dra[maxn];
int n, m, tag;
long long mn;
long long sw[maxn];
multiset<long long> s;
multiset<long long>::iterator iter;

inline long long fc(long long A, long long B, long long P){
    bool tag = false; if(B < 0){B = -B; tag = true;}
    long long ret = 0, tmp = A; 
    while(B){
        if(B & 1) ret = (ret + tmp) % P;
        tmp = (tmp + tmp) % P; B >>= 1;
    }
    return (tag) ? -ret : ret;
}

long long Gcd(long long a, long long b){return (a % b == 0) ? (b) : (Gcd(b, a % b));}

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

inline void putit(){
    scanf("%d%d", &n, &m); long long lin; s.clear(); tag = 0; mn = 0; s.insert(0);
    for(int i = 1; i <= n; ++i) scanf("%lld", &dra[i].ai);
    for(int i = 1; i <= n; ++i) scanf("%lld", &dra[i].pi);
    for(int i = 1; i <= n; ++i) scanf("%lld", &sw[i]);
    for(int i = 1; i <= m; ++i){scanf("%lld", &lin); s.insert(-lin);}
}

inline void prepare(){
    long long lin;
    for(int i = 1; i <= n; ++i){
        iter = s.lower_bound(-dra[i].ai); lin = *iter; if(!lin) iter--; lin = *iter;
        dra[i].atk = (-1) * (lin); s.erase(iter); s.insert(-sw[i]);
        mn = max(mn, ((dra[i].ai + dra[i].atk - 1) / dra[i].atk) );
    }
}

inline void workk(){
    long long g, inv, lin;
    for(int i = 1; i <= n; ++i){
        g = Gcd(dra[i].atk, dra[i].pi);
        if(dra[i].ai % g != 0){tag = 1; return;}
        dra[i].atk /= g; dra[i].pi /= g; dra[i].ai /= g;
        exgcd(dra[i].atk, dra[i].pi, inv, lin); 
        inv = (inv % dra[i].pi + dra[i].pi) % dra[i].pi;
        dra[i].data = fc(inv, dra[i].ai, dra[i].pi);
    }
}

inline void excrt(){
    lpl ret, lin = dra[1]; long long a, b, x, y, g;
    for(int i = 2; i <= n; ++i){
        lpl qwe = dra[i]; if(lin.data > qwe.data) swap(lin, qwe);
        g = Gcd(lin.pi, qwe.pi); if((qwe.data - lin.data) % g != 0){tag = 1; return;}
        lin.pi /= g; qwe.pi /= g;
        exgcd(lin.pi, qwe.pi, x, y); ret.pi = lin.pi * qwe.pi * g;
        x = fc(x, ((qwe.data - lin.data) / g), ret.pi); ret.data = fc(lin.pi * g, x, ret.pi); ret.data = (ret.data + lin.data) % ret.pi;
        lin = ret;
    }
    if(lin.data >= mn){printf("%lld\n", lin.data); return;}
    long long k = (mn - lin.data) / lin.pi; lin.data += k * lin.pi;
    while(lin.data < mn) lin.data += lin.pi;
    printf("%lld\n", lin.data);
}

int main()
{
    int T; scanf("%d", &T);
    while(T--){
        putit();
        prepare();
        workk();
        if(tag){printf("-1\n"); continue;}
        excrt();
        if(tag){printf("-1\n"); continue;}
    }
    return 0;
}

uoj396 [NOI2018]屠龍勇士