[NOI2018]屠龙勇士

题目描述

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

  • 游戏的目标是按照编号1→n1 \rightarrow n1n 顺序杀掉nnn 条巨龙,每条巨龙拥有一个初始的生命值aia_iai 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 pip_ipi ,直至生命值非负。只有在攻击结束后且当生命值恰好000 时它才会死去。

  • 游戏开始时玩家拥有mmm 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一 把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。 小D 觉得这款游戏十分无聊,但最快通关的玩家可以获得ION2018 的参赛资格, 于是小D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:

  • 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作为武器。

  • 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的xxx 次,使巨龙的生命值减少x×ATKx \times ATKx×ATK 。

  • 之后,巨龙会不断使用恢复能力,每次恢复pip_ipi 生命值。若在使用恢复能力前或某一次恢复后其生命值为000 ,则巨龙死亡,玩家通过本关。

那么显然机器人的攻击次数是决定能否最快通关这款游戏的关键。小 D 现在得知了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数xxx 设置为多少,才能用最少的攻击次数通关游戏吗?

当然如果无论设置成多少都无法通关游戏,输出−1-11 即可。

输入输出格式

输入格式:

从文件dragon.in 中读入数据。

第一行一个整数T ,代表数据组数。

接下来T 组数据,每组数据包含555 行。

  • 每组数据的第一行包含两个整数,nnn 和mmm ,代表巨龙的数量和初始剑的数量;

  • 接下来一行包含nnn 个正整数,第iii 个数表示第iii 条巨龙的初始生命值aia_iai ;

  • 接下来一行包含nnn 个正整数,第iii 个数表示第iii 条巨龙的恢复能力pip_ipi ;

  • 接下来一行包含nnn 个正整数,第iii 个数表示杀死第iii 条巨龙后奖励的剑的攻击力;

  • 接下来一行包含mmm 个正整数,表示初始拥有的mmm 把剑的攻击力。

输出格式:

输出到文件dragon.out 中。 一共TTT 行。

iii 行一个整数,表示对于第iii 组数据,能够使得机器人通关游戏的最小攻击次数xxx ,如果答案不存在,输出−1-11。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

拓中,带系数的拓中。

将每个式子化成 x ≡ a (mod p) 的形式,然后拓中直接求。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 10000000000001ll
#define N 200050
inline ll rd()
{
    ll f=1,c=0;char ch = getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=(c<<3)+(c<<1)+ch-'0';ch=getchar();}
    return f*c;
}
ll T,n,m;
struct sword
{
    int ch[N][2],fa[N],rt,tot,rep[N];
    ll w[N];
    void rotate(int x)
    {
        int y = fa[x],z = fa[y],k = (ch[y][1]==x);
        ch[y][k] = ch[x][!k],fa[ch[x][!k]]=y;
        ch[x][!k] = y,fa[y] = x;
        ch[z][ch[z][1]==y] = x,fa[x] = z;
    }
    void splay(int x,int goal)
    {
        while(fa[x]!=goal)
        {
            int y = fa[x],z = fa[y];
            if(z!=goal)
                ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
            rotate(x);
        }
        if(!goal)rt=x;
    }
    int findr(ll x)
    {
        int ret = rt,u = rt;
        while(u){if(w[u]>x)ret=u;u=ch[u][w[u]<=x];}
        splay(ret,0);
        return ret;
    }
    int findl(ll x)
    {
        int ret = rt,u = rt;
        while(u){if(w[u]<x)ret=u;u=ch[u][w[u]<x];}
        splay(ret,0);
        return ret;
    }
    ll find(ll x)
    {
        int ret = rt,u = rt;
        while(u){if(w[u]<x)ret=u;if(w[u]==x)return x;u=ch[u][w[u]<x];}
        splay(ret,0);
        return w[ret];
    }
    void insert(ll k)
    {
        int u = rt,f=rt;
        while(u&&w[f]!=k)f=u,u=ch[u][w[u]<k];
        if(w[f]==k)
        {
            rep[f]++;
            return ;
        }
        u=++tot;
        if(f)ch[f][k>w[f]]=u;
        fa[u]=f,rep[u]=1,w[u]=k;
        ch[u][0]=ch[u][1]=0;
        splay(u,0);
    }
    void erase(ll k)
    {
        int r = findr(k),l = findl(k);
        splay(l,0);splay(r,l);
        if(rep[ch[r][0]]>1)
        {
            rep[ch[r][0]]--;
        }else fa[ch[r][0]]=0,ch[r][0]=0;
    }
    void clear()
    {
        rt=tot=0;
    }
}sw;
ll ai[N],pi[N],wi[N],mx;
void init()
{
    sw.clear();
    sw.insert(inf);
    sw.insert(-1);
    mx=-1;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    ll ret = exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ret;
}
ll mul(ll x,ll y,ll mod)
{
    ll ret = 0;
    while(y)
    {
        if(y&1)ret=(ret+x)%mod;
        x=(x+x)%mod;
        y>>=1;
    }
    return ret;
}
ll zhx[N],jdr[N];
int fkzhx()
{
    ll x,y,wk;
    for(int i=1;i<=n;i++)
    {
        wk = sw.find(ai[i]);if(wk<0)wk=sw.w[sw.findr(ai[i])];sw.erase(wk);sw.insert(wi[i]);
        ll gcd = exgcd(wk,pi[i],x,y);
        if(ai[i]%gcd)return 0;
        jdr[i] = pi[i]/gcd;
        x = mul(x,ai[i]/gcd,jdr[i]);
        x = (x%jdr[i]+jdr[i])%jdr[i];
        zhx[i] = x;
        mx=max(mx,ai[i]/wk);
    }
    return 1;
}
ll excrt()
{
    ll A = 0,P = 1,x,y;
    for(int i=1;i<=n;i++)
    {
        ll a = P , b = jdr[i] , c = ((zhx[i]-A)%b+b)%b;//取模,不然会死 
        ll gcd = exgcd(a,b,x,y);
        if(c%gcd)return -1;
        P *= jdr[i]/gcd;
        x = (x%P+P)%P,c = (c%P+P)%P;
        x = mul(x,c,P);
        A = (A + mul(P/jdr[i],x,P))%P;
    }
    A = (A%P+P)%P;
    if(A<mx)return A+((mx-A)/P+(mx%A!=0))*P;//不加特判会挂 
    return A;
}
int main()
{
    T = rd();
    while(T--)
    {
        init();
        n=rd(),m=rd();
        for(int i=1;i<=n;i++)
            ai[i]=rd();
        for(int i=1;i<=n;i++)
            pi[i]=rd();
        for(int i=1;i<=n;i++)
            wi[i]=rd();
        for(int i=1;i<=m;i++)
            sw.insert(rd());
        int fk = 1;
        for(int i=1;i<=n&&fk;i++)
            if(pi[i]!=1)
                fk=0;
        if(fk)
        {
            ll ans = 0,wk;
            for(int i=1;i<=n;i++)
            {
                wk = sw.find(ai[i]);if(wk<0)wk=sw.w[sw.findr(ai[i])];sw.erase(wk);sw.insert(wi[i]);
                ans = max(ans,ai[i]/wk+(ai[i]%wk!=0));
            }
            printf("%lld\n",ans);
        }else
        {
            int r = fkzhx();
            if(!r)printf("-1\n");
            else printf("%lld\n",excrt());
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/9734008.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值