zoukankan      html  css  js  c++  java
  • BZOJ5418 NOI2018屠龙勇士EXCRT

    https://www.lydsy.com/JudgeOnline/problem.php?id=5418

    题目描述

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

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

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

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

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

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

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

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

    输入输出格式

    输入格式:

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

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

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

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

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

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

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

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

    输出格式:

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

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

    首先鸣谢ysy20021208帮助我踩坑,我才AC此题。

    一眼扩展中国剩余定理
    Pi × y+life=X×ATK
    ATK×X ≡life(mod Pi)
    板子题,解决!
    纯属瞎扯!
    国赛怎么可能这么水,即使是T1
    EXCRT使用是有限制的,那就是X的系数必须为1,而现在的X系数为ATK。
    这个ATK有可能在mod Pi的情况下有可能根本没有逆元,直接除更是不可以。
    我们求解如何消去ATK?
    使用exgcd算法求解一般的不定方程,解出特解,从而算出通解。
    X×ATK+Pi​y=life​
    用exgcd求出两个特解Sx和Sy
    x=Sx+k× (Pi/gcd(ATK​,Pi​))
    两边同时取模
    x≡Sx(mod Pi /gcd(ATK​,Pi​) ​​)
    之后EX中国剩余定理出场与前面的合并解决。
    解决了吗?
    没有。
    如果所有的Pi=Ai的话我们解同余方程的结果将会是0.但显然不对,应该直接求出杀死每条龙所需的刀数然后所有刀数求一个lcm即可。解方程的时候要扔掉。还有就是ATK是Pi的倍数是永远杀不掉龙的。
    我们在确定是哪把刀时,要开一个multiset和一个桶,这是最关键的。

    最后放代码

    #include<cstdio>
    #include<set>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define N 1000001
    typedef long long ll;
    multiset <ll> s;
    ll m[N];
    ll a[N];
    ll life[N];
    ll p[N];
    ll gg[N];
    bool flag;
    ll t[N];
    ll boom[N];
    ll T,n,K;
    ll maxn;
    ll pow(ll x,ll y,ll mod)
    {
        ll ans=0;
        while(y)
        {
            if(y&1)
                ans=(ans+x)%mod;
            x=(x+x)%mod;
            y/=2;
        }
        return ans;
    }
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b)
        {
            x=1;
            y=0;
            return a;
        }
        ll gcd=exgcd(b,a%b,x,y);
        ll tmp=x;
        x=y;
        y=tmp-a/b*y;
        return gcd;
    }
    ll find(ll num)
    {
        multiset <ll> ::iterator here=s.lower_bound(num);
        if(here==s.end())
        {
        	here--;
        	return -*here;
        }
        else
        	return -*here;
    }
    void in()
    {
        for(int i=1;i<=n;i++)
        {
            t[i]=find(-life[i]);
            s.insert(-gg[i]);
            boom[gg[i]]++;
            if((--boom[t[i]])==0)
                s.erase(-t[i]);
        }
        for(int i=1;i<=n;i++)
            maxn=max(maxn,(life[i]%t[i])?(life[i]/t[i]+1):(life[i]/t[i]));
    }
    void is()
    {
        for(int i=1;i<=n;i++)
        {
            ll x,y;
            ll gcd=exgcd(t[i],p[i],x,y);
            if(life[i]%gcd)
            {
            	flag=1;
            	return ;
            }
            x=pow(x,(life[i]/gcd),(p[i]/gcd));
            a[i]=x;
            m[i]=p[i]/gcd;
        }
    }
    void init()
    {
        s.clear();
        flag=0;
        ll x;
        maxn=0;
        memset(boom,0,sizeof(boom));
        memset(m,0,sizeof(m));
        memset(a,0,sizeof(a));
        scanf("%lld%lld",&n,&K);
        for(int i=1;i<=n;i++)
        	scanf("%lld",&life[i]);
        for(int i=1;i<=n;i++)
        	scanf("%lld",&p[i]);
        for(int i=1;i<=n;i++)
        	scanf("%lld",&gg[i]);
        for(int i=1;i<=K;i++)
        {
        	scanf("%lld",&x);
        	boom[x]++;
        	s.insert(-x);
        }
        in();
        is();
    }
    ll China()
    {
        if(flag)
            return -1;
        ll M=m[1],olda=a[1];
        for(int i=2;i<=n;i++)
        {
            ll A=M,B=m[i],d=((a[i]-olda)%B+B)%B,x,y;
            ll gcd=exgcd(A,B,x,y);
            if(d%gcd)
                return -1;
            x=pow(x,d/gcd,B/gcd);
            M*=B/gcd;
            olda=(olda+x*A)%M;
        }
        if(olda<maxn)
        	olda=olda+M*(((maxn-olda)%M)?((maxn-olda)/M+1):((maxn-olda)/M));
        else if(olda>maxn)
        	olda=olda-M*((-maxn+olda)/M);
        return olda;
    }
    int main()
    {
        scanf("%lld",&T);
        while(T--)
        {
            init();
            printf("%lld
    ",China());
        }
        return 0;
    }
    

      原网站地址

    https://www.cnblogs.com/342zhuyongqi/

  • 相关阅读:
    vue跨域代理配置
    vue中引入jquery
    vue中使用特殊字体
    vue中使用mockjs
    vue中使用动态echart图表
    解决win10休眠后无法唤醒
    nvm-windows的安装配置
    黑苹果快捷键
    python基础知识
    如何高效的学习python
  • 原文地址:https://www.cnblogs.com/342zhuyongqi/p/9860902.html
Copyright © 2011-2022 走看看