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/

原文地址:https://www.cnblogs.com/342zhuyongqi/p/9860902.html