zoukankan      html  css  js  c++  java
  • NOI2018/LuoGu P4774屠龙勇士

    本蒟蒻终于屠龙成功!!

    作为一个我的世界的资深玩家,对屠龙有着无比的信仰和热情!!

    首先吐槽一下这只信息龙,它变成负HP后居然不会死,只有他自己回血回到了0HP才算死23333

    来我们来看看题意描述,国赛的题意描述略长

    这道题其实没有那么的可怕,当时我写完excrt就有学长推荐我来写

    题目描述

    小 D 最近在网上发现了一款小游戏。游戏的规则如下: • 游戏的目标是按照编号 1~n 顺序杀掉 n 条巨龙,每条巨龙拥有一个初始的生命 值 a i 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每 次增加 p i ,直至生命值非负。只有在 . 攻 . 击 . 结 . 束 . 后且当生命值 . 恰 . 好为 0 时它才会 死去。 • 游戏开始时玩家拥有 m 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格,于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:• 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中.攻.击.力.最.大的一把剑作为武器。如果没有这样的剑,则选择..击.力.最.低的一把剑作为武器。• 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙.固.定.的 x 次,使巨龙的生命值减少 x × ATK 。• 之后,巨龙会不断使用恢复能力,每次恢复 p i 生命值。若在使用恢复能力前或某一次恢复后其生命值为 0 ,则巨龙死亡,玩家通过本关。那么显然机器人的.攻.击.次.数是决定能否最快通关这款游戏的关键。小 D 现在得知 了每条巨龙的所有属性,她想考考你,你知道应该将机器人的攻击次数 x 设置为多少,才能用最少的攻击次数通关游戏吗?当然如果无论设置成多少都无法通关游戏,输出-1 即可。

    输入格式

    从文件 dragon.in 中读入数据。 第一行一个整数 T ,代表数据组数。 接下来 T 组数据,每组数据包含 5 行。 • 每组数据的第一行包含两个整数,n 和 m ,代表巨龙的数量和初始剑的数量; • 接下来一行包含 n 个正整数,第 i 个数表示第 i 条巨龙的初始生命值 a i ; • 接下来一行包含 n 个正整数,第 i 个数表示第 i 条巨龙的恢复能力 p i ; • 接下来一行包含 n 个正整数,第 i 个数表示杀死第 i 条巨龙后奖励的剑的攻击 力; • 接下来一行包含 m 个正整数,表示初始拥有的 m 把剑的攻击力。

    输出格式

    输出到文件 dragon.out 中。 一共 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
    

    样例 1 解释

    第一组数据:
    • 开始时拥有的剑的攻击力为 {1,9,10},第 1 条龙生命值为 3,故选择攻击力为 1的剑,攻击 59 次,造成 59 点伤害,此时龙的生命值为-56,恢复 14 次后生命值
    恰好为 0,死亡。• 攻击力为 1 的剑消失,拾取一把攻击力为 7 的剑,此时拥有的剑的攻击力为{7,9,10},第 2 条龙生命值为 5,故选择攻击力为 7 的剑,攻击 59 次,造成 413点伤害,此时龙的生命值为-408,恢复 68 次后生命值恰好为 0,死亡。• 此时拥有的剑的攻击力为 {3,9,10},第 3 条龙生命值为 7,故选择攻击力为 3 的
    剑,攻击 59 次,造成 177 点伤害,此时龙的生命值为-170,恢复 17 次后生命值恰好为 0,死亡。
    • 没有比 59 次更少的通关方法,故答案为 59。
    第二组数据:
    • 不存在既能杀死第一条龙又能杀死第二条龙的方法,故无法通关,输出-1。
    

    子任务

    特性 1 是指:对于任意的 i,a i ≤ p i 。
    特性 2 是指:LCM(p i ) ≤ 10 6 即所有 p i 的最小公倍数不大于 10 6 。
    对于所有的测试点,T ≤ 5 ,所有武器的攻击力 ≤ 10 6 ,所有 p i 的.最.小.公.倍.数≤ 10 12 。
    

    你所用到的中间结果可能很大,注意保存中间结果的变量类型。

    限制与约定

    时间限制2s2s

    空间限制512MB

    好了我们来看看这道题的思路是什么

    首先题要读懂!!我就是读错了题导致WA了三个点(数据好水居然只WA了三个)

    通过题干可得(heal是回复,atk是攻击)

    ATK*x = hp + heal*y

    然后呢我们mod一个heal

    ATK*x = hp + heal*y(% heal})

    $AT{K_i}*x = h{p_i}(\% hea{l_i})$

    就很明了了,是一个ex中国剩余定理,因为x是固定的,取模数不一定是质数

    现在的问题是x前面有一个讨厌的系数,它应该怎么弄掉,对,把它除到右面就好了

    $x = h{p_i}*ATK_i^{ - 1}(\% hea{l_i})$

    很明显就是求一个ATK关于heali的逆元(注意先约分再求逆元,除了零以外,所有两个互质的数之间都存在逆元)

    做题的好习惯是看数据范围,看到前几组数据了吗,显然攻击力恢复力全是1,excrt是过不了的,那也很简单,只要把它砍成刚变成负值就好了,也很简单

    但是看到后面的数据范围十分庞大,显然在选剑的时候回TLE,那么就需要一些数据结构,用multiset就好(不用set因为有重复元素)

    这里用到了一个函数叫upperbound,它会返回最后一个大于等于它的数的迭代器,再- -就是选的剑,这个是set的存储特点,注意每次都clear()一下就OK

    上代码!

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<set>
      5 using namespace std;
      6 typedef long long ll;
      7 #define N 100011
      8 #define M 100011
      9 #define rg register
     10 ll T,n,m,x,y;bool fl=1;
     11 ll hp[N],reward[N],heal[N],sword,r[N],a[N];
     12 multiset<ll>S;
     13 namespace ldy
     14 {
     15     ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
     16     ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
     17     ll ksc(ll a,ll b,ll mod)
     18     {
     19         ll fina=0,kk=1;
     20         if(a<0)a=-a,kk=-kk;
     21         if(b<0)b=-b,kk=-kk;
     22         while(b)
     23         {
     24             if(b%2)fina=(fina+a)%mod;
     25             b>>=1,a=(a+a)%mod;
     26         }
     27         return fina%mod*kk;
     28     }
     29     ll read()
     30     {
     31         ll f=1,x=0;
     32         char ss=getchar();
     33         while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
     34         while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
     35         return f*x;
     36     }
     37     void ex_gcd(ll a,ll b)
     38     {
     39         if(!b)x=1,y=0;
     40         else
     41         {
     42             ex_gcd(b,a%b);
     43             ll tt=x;x=y;y=tt-a/b*x;
     44         }
     45     }
     46     ll exgcd(ll a,ll b,ll c)
     47     {
     48         ll gc=gcd(a,b);
     49         if(c%gc)return -1;
     50         a/=gc,b/=gc,c/=gc;
     51         ex_gcd(a,b);
     52         return (ksc(x,c,b)+b)%b;
     53     }
     54 }
     55 using namespace ldy;
     56 void init()
     57 {
     58     for(rg int i=1;i<=n;i++)
     59     {
     60         multiset<ll>::iterator it =S.upper_bound(hp[i]);
     61         if(it!=S.begin())it--;
     62         ll atk=*it;
     63         ll gc=gcd(atk,heal[i]);
     64         atk/=gc,hp[i]/=gc,heal[i]/=gc;
     65         a[i]=heal[i],r[i]=ksc(hp[i],exgcd(atk,heal[i],1),heal[i]);
     66         S.erase(it),S.insert(reward[i]);
     67     }    
     68 }
     69 ll excrt()
     70 {
     71     for(int i=1;i<n;i++)
     72     {
     73         ll k0=exgcd(a[i],a[i+1],r[i+1]-r[i]);
     74         if(k0==-1)return -1;
     75         r[i+1]=a[i]*k0+r[i];
     76         a[i+1]=lcm(a[i],a[i+1]);
     77     }
     78     return exgcd(1,a[n],r[n]);
     79 }
     80 ll lie()
     81 {
     82     ll ans=-1;
     83     for(int i=1;i<=n;i++)
     84     {
     85         multiset<ll>::iterator it =S.upper_bound(hp[i]);
     86         if(it!=S.begin())it--;
     87         ll atk=*it;
     88         if(hp[i]%atk)ans=max(ans,hp[i]/atk+1);
     89         else ans=max(ans,hp[i]/atk);
     90         S.erase(it),S.insert(reward[i]);
     91     }
     92     return ans;
     93 }
     94 int main()
     95 {
     96     for(int tt=read();tt>0;tt--)
     97     {
     98         n=read(),m=read();fl=1;
     99         for(rg int i=1;i<=n;i++)hp[i]=read(); 
    100         for(rg int i=1;i<=n;i++){heal[i]=read();if(heal[i]!=1)fl=0;}
    101         for(rg int i=1;i<=n;i++)reward[i]=read();
    102         for(rg int i=1;i<=m;i++){sword=read();S.insert(sword);}
    103         if(fl)printf("%lld
    ",lie());
    104         else init(),printf("%lld
    ",excrt());
    105         S.clear();
    106     }                        
    107     return 0;
    108 }
  • 相关阅读:
    LeetCode Power of Three
    LeetCode Nim Game
    LeetCode,ugly number
    LeetCode Binary Tree Paths
    LeetCode Word Pattern
    LeetCode Bulls and Cows
    LeeCode Odd Even Linked List
    LeetCode twoSum
    549. Binary Tree Longest Consecutive Sequence II
    113. Path Sum II
  • 原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10096955.html
Copyright © 2011-2022 走看看