[LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士

题意

题面好啰嗦啊直接粘LOJ题面好了

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

  • 游戏的目标是按照编号 \(1\)~\(n\) 顺序杀掉 \(n\) 条巨龙,每条巨龙拥有一个初始的生命值 \(a_i\) 。同时每条巨龙拥有恢复能力,当其使用恢复能力时,它的生命值就会每次增加 \(p_i\),直至生命值非负。只有在攻击结束后且当生命值恰好为 \(0\) 时它才会死去。
  • 游戏开始时玩家拥有 \(m\) 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。

小 D 觉得这款游戏十分无聊,但最快通关的玩家可以获得 ION2018 的参赛资格, 于是小 D 决定写一个笨笨的机器人帮她通关这款游戏,她写的机器人遵循以下规则:

  • 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作为武器。
  • 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 \(x\) 次,使巨龙的生命值减少 \(x \times ATK\)。
  • 之后,巨龙会不断使用恢复能力,每次恢复 \(p_i\) 生命值。若在使用恢复能力前或某一次恢复后其生命值为 \(0\),则巨龙死亡,玩家通过本关。

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

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

杀龙的时候需要三步必杀, 不能重复多次qwq...

\(n\le 10^5,m\le 10^5,a_i\le 10^{12}\).

对于所有的测试点,\(T \le 5\),所有武器的攻击力 \(\le 10^6\),所有 \(p_i\) 的最小公倍数 \(\le 10^{12}\)。

题解

乍一看这题神仙的一匹, 然而冷静分析一下可以发现:

拿来淦龙的剑都是固定的, 而且每次相当于把龙的血打到一个不大于 \(0\) 的 \(p_i\) 的倍数就可以完成任务了.

那么也就是说只要让 \(x\) 满足:

\[x\times ATK_i\equiv a_i \pmod {p_i}\\
x\times ATK_i\ge a_i
\]

先来搞第一个限制.

不难发现这个限制相当于下式:

\[x\times ATK_i+k\times p_i=a_i
\]

其中 \(ATK_i,p_i,a_i\) 都是确定的, 显然这个东西可以随手 ExGCD 搞一搞解出一个 \(\bmod p_i\) 意义下的 \(x\).

不过注意这一步要对 \(ATK_i\) 和 \(p_i\) 进行约分, 不然逆元不唯一就会解出奇怪的东西qaq(sb rvalue在这坑了一个小时)...

然后我们不难发现我们得到了一堆形如这样的方程组:

\[x\equiv r_i \pmod {p_i}
\]

这不裸的 CRT 么?

然而 \(p_i\) 不互质. 并不能直接 CRT.

考虑 ExCRT. ExCRT 的大体思路是通过 ExGCD 来合并两个同余方程.

假设我们现在有两个同余方程:

\[\begin{cases}
x\equiv a &\pmod n\\
x\equiv b &\pmod m
\end{cases}
\]

不难发现它等价于:

\[\begin{cases}
x = a + pn\\
x = b + qm
\end{cases}
\]

那么也就是说:

\[a+pn=b+qm
\]

移项可得:

\[a-b=qm-pn
\]

好了我们可以 ExGCD 了.

算出 \(p\) 和 \(q\) 之后可以用 \(x=a+pn=b+pm\) 算出 \(x\) 来. 它与所有 \(\bmod \gcd(n,m)\) 意义下同余的值都是这两个方程的解. 显然我们直接对 \(\gcd(n,m)\) 取模就可以得到最小值了.

一直这样合并下去, 只要 ExGCD 的时候出锅那么根据Bézout定理这个方程组无解.

然后我们可以得到一个 \(\bmod \operatorname{lcm} \{p_i\}\) 的 \(x\). 接着考虑第二种限制.

显然我们可以对当前已有的 \(x\) 计算它是否满足 \(x\times ATK_i\ge a_i\), 如果不满足的话把 \(x\) 变为 \(\bmod \operatorname{lcm} \{p_i\}\) 意义下同余的最小满足条件的值就可以了. 不难发现答案就是:

\[x+\operatorname{lcm}\{p_i\}\times \max_{1\le i\le n}\left \lceil \frac {\left \lceil \frac{a_i}{ATK_i}\right \rceil-x}{\operatorname{lcm}\{p_i\}}\right \rceil
\]

UOJ因为有Hack所以数据比LOJ强一些, LOJ过了之后建议在UOJ上交一发.

参考代码

下面这份代码在发文时没有被Hack qwq...

#include <bits/stdc++.h>

const int MAXN=1e5+10;
typedef long long intEx; struct Equation{
intEx mod;
intEx rest;
};
Equation E[MAXN]; int n;
int m;
intEx a[MAXN];
intEx p[MAXN];
intEx w[MAXN];
intEx atk[MAXN]; intEx Mul(intEx,intEx,intEx);
intEx ExGCD(intEx,intEx,intEx&,intEx&); int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",a+i);
for(int i=1;i<=n;i++)
scanf("%lld",p+i);
for(int i=1;i<=n;i++)
scanf("%lld",w+i);
std::multiset<intEx> s;
for(int i=1;i<=m;i++){
intEx x;
scanf("%lld",&x);
s.insert(x);
}
try{
for(int i=1;i<=n;i++){
E[i].mod=p[i];
auto it=s.upper_bound(a[i]);
if(it!=s.begin())
--it;
intEx t;
atk[i]=*it;
s.erase(it);
intEx gcd=ExGCD(atk[i],p[i],E[i].rest,t);
if(a[i]%gcd!=0)
throw std::logic_error(R"(a[i]%gcd!=0)");
E[i].mod/=gcd;
E[i].rest=Mul(a[i]/gcd,E[i].rest,E[i].mod);
(E[i].rest+=E[i].mod)%=E[i].mod;
s.insert(w[i]);
}
for(int i=2;i<=n;i++){
intEx x,y;
intEx gcd=ExGCD(E[i-1].mod,E[i].mod,x,y);
intEx lcm=E[i-1].mod/gcd*E[i].mod;
if((E[i-1].rest-E[i].rest)%gcd!=0)
throw std::logic_error(R"((E[i].rest-E[i-1].rest)%gcd!=0 @)"+std::to_string(i));
intEx scale=(E[i-1].rest-E[i].rest)/gcd;
(E[i].rest+=Mul(Mul(scale,y,lcm),E[i].mod,lcm))%=lcm;
E[i].mod=lcm;
E[i].rest=(E[i].rest+lcm)%lcm;
}
intEx scale=0;
for(int i=1;i<=n;i++)
scale=std::max(scale,((a[i]+atk[i]-1)/atk[i]-E[n].rest+E[n].mod-1)/E[n].mod);
printf("%lld\n",E[n].rest+scale*E[n].mod);
}
catch(std::logic_error x){
puts("-1");
continue;
}
}
return 0;
} intEx ExGCD(intEx a,intEx b,intEx& x,intEx& y){
if(b==0){
x=1;
y=0;
return a;
}
intEx gcd=ExGCD(b,a%b,y,x);
y-=(a/b)*x;
return gcd;
} intEx Mul(intEx a,intEx b,intEx p){
return __int128(a)*b%p;
}

[LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士的更多相关文章

  1. [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程

    [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程 题意 给定一张无向图, 每条边有一个距离和一个高度. 再给定 \(q\) 组可能在线的询问, 每组询问给定一个点 ...

  2. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  3. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

  4. [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分

    [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分 题意 给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案 \(| ...

  5. NOI 2018 屠龙勇士 (拓展中国剩余定理excrt+拓展欧几里得exgcd)

    题目大意:略 真是一波三折的一道国赛题,先学了中国剩余定理,勉强看懂了模板然后写的这道题 把取出的宝剑攻击力设为T,可得Ti*x=ai(mod pi),这显然是ax=c(mod b)的形式 这部分用e ...

  6. [LOJ 2720][BZOJ 5417][UOJ 395][NOI 2018]你的名字

    [LOJ 2720][BZOJ 5417][UOJ 395][NOI 2018]你的名字 题意 给定一个大串 \(S\) 以及 \(q\) 次询问, 每次询问给定一个串 \(T\) 和区间 \([l, ...

  7. UOJ #449. 【集训队作业2018】喂鸽子

    UOJ #449. [集训队作业2018]喂鸽子 小Z是养鸽子的人.一天,小Z给鸽子们喂玉米吃.一共有n只鸽子,小Z每秒会等概率选择一只鸽子并给他一粒玉米.一只鸽子饱了当且仅当它吃了的玉米粒数量\(≥ ...

  8. LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)

    题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...

  9. loj#2721. 「NOI2018」屠龙勇士

    题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...

随机推荐

  1. java图形界面 计算器实现

    编写程序实现一个简单计算器的基本功能,具体可以模仿Windows附件中的计算器或模拟常见的实物计算器. package beizi; import java.awt.EventQueue; impor ...

  2. intellij idea从git检出代码并建立工程

    1. 打开intellij idea,点击configure,settings 2. 左侧展开Version Control,点击Git,点击下图中红框中按钮 3. 在弹出窗口中找到git.exe,点 ...

  3. models.py相关API

    models.py import datetime from django.db import models from django.utils import timezone class Quest ...

  4. vue动画实现方式

    vue动画实现方式 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&q ...

  5. selectpage选择订单的时候,订单数量和金额会动态改变

    1. 2. HTML部分: JS: PHP获取数据并return json

  6. Alpine Linux 安装 lxml Pillow 失败

    lixm 需要编译安装,因此需要先安装gcc g++ RUN apk add --update --no-cache g++ gcc libxslt-dev python3-dev openssl-d ...

  7. Java中的ThreadLocal

    关于 ThreadLocal,我们经常用它来解决多线程并发问题,那它究竟是如何做到的?今天就让我们来好好看一下. 从源码入手 首先,让我们看看 ThreadLocal 类中的介绍: This clas ...

  8. 【linux】切换到root用户,并重置root用户密码

    1.切换当前用户 到 root用户 sudo -i 2.重置root用户密码 sudo passwd root

  9. Core源码(三) Lazy<T>

    Lazy<T>解决什么问题? 1.大对象加载 考虑下面的需求,有个对象很大,创建耗时,并且要在托管堆上分配一大块空间.我们当然希望,用到它的时候再去创建.也就是延迟加载,等到真正需要它的时 ...

  10. ASP.NET MVC IOC依赖注入之Autofac系列开篇

    Autofac为IOC组件,实现控制反转,主要结合面向接口编程,完成较大程度的解耦工作. 使用IOC,必须面向接口编程,所谓的面向接口编程,即程序中依赖于抽象,而不依赖于具体实现. 需要所有的业务逻辑 ...