推导过程存在漏洞+exCRT板子没打熟于是期望得分÷实际得分=∞?

题目描述

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

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

  • 游戏开始时玩家拥有 \(m\) 把攻击力已知的剑,每次面对巨龙时,玩家只能选择一把剑,当杀死巨龙后这把剑就会消失,但作为奖励,玩家会获得全新的一把剑。

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

  • 每次面对巨龙时,机器人会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低的一把剑作为武器。
  • 机器人面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 \(x​\) 次,使巨龙的生命值减少 \(x\times 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

样例输入

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

样例输出

59
-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

子任务

测试点编号 $n$ $m$ $p_i$ $a_i$ 攻击力 其他限制
$1$ $\le 10^5$ $=1$ $=1$ $\le 10^5$ $=1$
$2$
$3$ $\le 10^5$
$4$
$5$ $\le 10^3$ $\le 10^3$ $\le 10^5$

特性 $1$、

特性 $2$

$6$
$7$
$8$ $=1$ $=1$ $\le 10^8$ $\le 10^8$ $\le 10^6$ 特性 $1$
$9$
$10$
$11$
$12$
$13$
$14$ $=10^5$ $=10^5$ $=1$ 无特殊限制
$15$
$16$ $\le 10^5$ $\le 10^5$

所有 $p_i$ 是质数

$\le 10^{12}$ 特性 $1$
$17$
$18$ 无特殊限制
$19$
$20$

特性 \(1\) 是指:对于任意的 \(i\),\(a_i\le p_i\)。

特性 \(2\) 是指:\(LCM(p_i)\le 10^6\) 即所有 \(p_i\) 的最小公倍数不大于 \(10^6\)。

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

提示

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

题解:

整道题使用 exCRT 就能弄过去。

首先我们考虑每一轮用哪把剑砍龙。由于龙的顺序是固定的,所以每次剩下的剑的集合是固定的。但是每一轮都有剑在动态变化,因此我们用一棵平衡树来维护每次需要用的剑。

此时我们可以预处理砍每条龙用的是哪把剑,令砍第 \(i\) 条龙用的剑攻击力为 \(c_i\)。

那么对于每把剑和相应的龙都应该存在一个 \(t\in\mathbb N\) ,使得

\[a_i-c_ix+tp_i=0
\]

把它转化为同余方程的形式即为

\[c_ix\equiv a_i\pmod{p_i}
\]

同时,我们要保证 \(x\) 取最小非负整数解时有意义,因此我们先用上面算出来的 \(c_i\) 分别求出每头龙至少需要砍多少下才会死,然后我们“提前”砍掉那么多。

即设变量 \(xmn\) 表示最少要砍的刀数

\[xmn=\max_{1\le i\le n}\left\{\left\lceil\frac{a_i}{c_i}\right\rceil\right\}
\]

那么对于所有的 \(a_i\) 都要减去一个 \(xmn\times c_i\)。

减过之后,对于所有的龙,我们把方程组列出来,有

\[\left\{
\begin{aligned}
&c_1x\equiv a_1\pmod{p_1}\\\
&c_2x\equiv a_2\pmod{p_2}\\\
&\cdots\\\
&c_nx\equiv a_n\pmod{p_n}
\end{aligned}
\right.
\]

变成了一个 CRT 的形式,由于 \(p_i\) 没有保证互质,所以我们使用 exCRT。

但是还有一点,我们用 CRT 解决问题时,左侧的 \(x\) 是没有系数的,我们要考虑怎么样把这边的系数化掉。

如果用逆元,两边同除 \(c_i\),那么只在 \(p_i\) 保证为质数的意义下才能成立,否则逆元无解导致题目答案错误。

我们可以用不定方程来推不定方程,因为 \(c_ix\equiv a_i\) 有一系列解,而且和 \(x\) 成线性关系,我们直接从这边转化过来就可以了。

\[c_ix\equiv a_i\pmod{p_i}\\\
c_ix+p_it=a_i,\ t\in \mathbb Z
\]

这里只有 \(x\) 和 \(t\) 是变量,因此只需要把 \(x\) 的特解和通解求出来,再构造一个形如 \(x\equiv b_i\pmod{d_i}\) 的方程就可以了。

对不定方程 \(c_ix+p_it=\gcd(c_i,p_i)\) 求解,得到 \(x=x_0\)。等式两边同乘 \(\frac{a_i}{\gcd(c_i,p_i)}\),\(x=\frac{x_0a_i}{\gcd(c_i,p_i)}\)。那么 \(\Delta x=\frac {p_i}{\gcd(c_i,p_i)}\)。

由此构造出了新方程

\[x\equiv \frac{x_0a_i}{\gcd(c_i,p_i)}\left(\bmod \frac{p_i}{\gcd(c_i,p_i)}\right)
\]

原方程组就变成了

\[\left\{
\begin{aligned}
&x\equiv b_1\pmod{d_1}\\\
&x\equiv b_2\pmod{d_2}\\\
&\cdots\\\
&x\equiv b_n\pmod{d_n}
\end{aligned}
\right.
\]

\(b_i,d_i\) 由上式计算。

然后套上 exCRT ,最后加上一开始算的 \(latex xmn\) 即可。

本来多简单一个题被我公式来公式去整这么复杂。

Code:

(平衡树(BST:: 部分)版面较大,multimap 可过)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#define ll long long
namespace BST
{
int ls[200100],rs[200100],key[200100],rdm[200100],sz[200100],pcnt=0,root=0;
int Newnode(int x)
{
++pcnt;
key[pcnt]=x;
rdm[pcnt]=rand();
ls[pcnt]=rs[pcnt]=0;
sz[pcnt]=1;
return pcnt;
}
void maintain(int rt)
{
sz[rt]=sz[ls[rt]]+sz[rs[rt]]+1;
}
int Merge(int a,int b)
{
if(!a||!b)
return a|b;
if(rdm[a]<rdm[b])
{
rs[a]=Merge(rs[a],b);
maintain(a);
return a;
}
ls[b]=Merge(a,ls[b]);
maintain(b);
return b;
}
void split(int rt,ll x,int &a,int &b)
{
if(!rt)
{
a=b=0;
return;
}
if(key[rt]<=x)//不高于
{
a=rt;
split(rs[a],x,rs[a],b);
}
else
{
b=rt;
split(ls[b],x,a,ls[b]);
}
maintain(rt);
}
void Insert(int x)
{
int a,b;
split(root,x,a,b);
root=Merge(Merge(a,Newnode(x)),b);
}
void Delete(int x)
{
int a,b,c;
split(root,x-1,a,b);
split(b,x,b,c);
b=Merge(ls[b],rs[b]);
root=Merge(Merge(a,b),c);
}
int getMin(int rt)
{
if(ls[rt])
return getMin(ls[rt]);
return key[rt];
}
int getMax(int rt)
{
if(rs[rt])
return getMax(rs[rt]);
return key[rt];
}
int getsword(ll x)
{
int a,b,ans;
split(root,x,a,b);
if(!sz[a])
ans=getMin(b);
else
ans=getMax(a);
root=Merge(a,b);
return ans;
}
} ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1,y=0;
return a;
}
ll g=exgcd(b,a%b,y,x);
y-=a/b*x;
return g;
}
ll qmul(ll x,ll y,ll p)
{
ll ans=0,f=1;
if(x<0)
{
x=-x;
f=-f;
}
if(y<0)
{
y=-y;
f=-f;
}
while(y)
{
if(y&1)
ans=(ans+x)%p;
x=(x+x)%p;
y>>=1;
}
return ans*f;
}
ll k[100100],a[100100],b[100100],c[100100];//k 指系数
//c 是奖励的
int main()
{
freopen("dragon.in","r",stdin);
freopen("dragon.out","w",stdout);
int T,n,m;
ll x,y;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
BST::pcnt=BST::root=0;
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&b[i]);
for(int i=1;i<=n;++i)
scanf("%lld",&c[i]);
for(int i=1;i<=m;++i)
{
scanf("%lld",&x);
BST::Insert(x);
}
ll xmn=0;
for(int i=1;i<=n;++i)
{
ll f=BST::getsword(a[i]);
BST::Delete(f);
BST::Insert(c[i]);
c[i]=f;
xmn=xmn>ceil((double)a[i]/f)?xmn:ceil((double)a[i]/f);
}
for(int i=1;i<=n;++i)
a[i]-=c[i]*xmn; bool flag=0;
for(int i=1;i<=n;++i)
{
//c[i]*x=a[i](mod b[i])
ll g=exgcd(c[i],b[i],x,y);
if(a[i]%g)
{
puts("-1");
flag=1;
break;
}
ll t=b[i]/g;
//特解 x
x=(x%t+t)%t;
x=qmul(x,a[i]/g,t);
a[i]=x;
b[i]/=g;//公差
if(i==1)
continue;
g=exgcd(b[i],b[i-1],x,y);
if((a[i]-a[i-1])%g)
{
puts("-1");
flag=1;
break;
}
t=b[i-1]/g;
x=(x%t+t)%t;
x=qmul(x,(a[i]-a[i-1])/g,t);
a[i]-=qmul(b[i],x,b[i]/g*b[i-1]);
b[i]=b[i]/g*b[i-1];
a[i]=(a[i]%b[i]+b[i])%b[i];
}
if(!flag)
printf("%lld\n",xmn+((a[n]%b[n])+b[n])%b[n]);
}
return 0;
}

洛谷 P4774 / loj 2721 [NOI2018] 屠龙勇士 题解【同余】【exgcd】【CRT】的更多相关文章

  1. 洛谷P4774 BZOJ5418 LOJ2721 [NOI2018]屠龙勇士(扩展中国剩余定理)

    题目链接: 洛谷 BZOJ LOJ 题目大意:这么长的题面,就饶了我吧emmm 这题第一眼看上去没法列出同余方程组.为什么?好像不知道用哪把剑杀哪条龙…… 仔细一看,要按顺序杀龙,所以获得的剑出现的顺 ...

  2. LOJ.2721.[NOI2018]屠龙勇士(扩展CRT 扩展欧几里得)

    题目链接 LOJ 洛谷 rank前3无压力(话说rank1特判打表有意思么) \(x*atk[i] - y*p[i] = hp[i]\) 对于每条龙可以求一个满足条件的\(x_0\),然后得到其通解\ ...

  3. Luogu P4774 / LOJ2721 【[NOI2018]屠龙勇士】

    真是个简单坑题...++ 前置: exgcd,exCRT,STL-multiset 读完题不难发现,攻击每条龙用的剑都是可以确定的,可以用multiset求.攻击最少显然应该对于每一条龙都操作一次,即 ...

  4. 洛谷 P3239 / loj 2112 [HNOI2015] 亚瑟王 题解【期望】【DP】

    ???看不懂的期望DP 题目描述 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑. 他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂亮.众所周知,亚 ...

  5. 洛谷 P4108 / loj 2119 [HEOI2015] 公约数数列 题解【分块】

    看样子分块题应该做的还不够. 题目描述 设计一个数据结构. 给定一个正整数数列 \(a_0, a_1, \ldots , a_{n-1}\),你需要支持以下两种操作: MODIFY id x: 将 \ ...

  6. 洛谷 P4269 / loj 2041 [SHOI2015] 聚变反应炉 题解【贪心】【DP】

    树上游戏..二合一? 题目描述 曾经发明了零件组装机的发明家 SHTSC 又公开了他的新发明:聚变反应炉--一种可以产生大量清洁能量的神秘装置. 众所周知,利用核聚变产生的能量有两个难点:一是控制核聚 ...

  7. [洛谷P4774] [NOI2018]屠龙勇士

    洛谷题目链接:[NOI2018]屠龙勇士 因为markdown复制过来有点炸格式,所以看题目请戳上面. 题解: 因为杀死一条龙的条件是在攻击\(x\)次,龙恢复\(y\)次血量\((y\in N^{* ...

  8. P4774 [NOI2018]屠龙勇士

    P4774 [NOI2018]屠龙勇士 先平衡树跑出打每条龙的atk t[] 然后每条龙有\(xt \equiv a[i](\text{mod }p[i])\) 就是\(xt+kp[i]=a[i]\) ...

  9. 【BZOJ5418】【NOI2018】屠龙勇士(数论,exgcd)

    [NOI2018]屠龙勇士(数论,exgcd) 题面 洛谷 题解 考场上半个小时就会做了,一个小时就写完了.. 然后发现没过样例,结果大力调发现中间值爆\(longlong\)了,然后就没管了.. 然 ...

随机推荐

  1. radiobutton 选中的项不能去掉选择的问题

    代码如下: RadioButton rbtn = new RadioButton(getApplicationContext()); rbtn.setText(String.valueOf(item. ...

  2. promise、resolve、reject、拦截响应

    Promise是一个接口,它用来处理的对象具有这样的特点:在未来某一时刻(主要是异步调用)会从服务端返回或者被填充属性.其核心是,promise是一个带有then()函数的对象. 使用promise机 ...

  3. CentOS 7上源码编译安装和配置LNMP Web+phpMyAdmin服务器环境

    CentOS 7上源码编译安装和配置LNMP Web+phpMyAdmin服务器环境 什么是LNMP? LNMP(别名LEMP)是指由Linux, Nginx, MySQL/MariaDB, PHP/ ...

  4. (匹配 Hopcroft-Karp算法)Rain on your Parade -- Hdu --2389

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=2389 不能用匈牙利,会TEL的,用Hopcroft-Karp Hopcroft-Karp课件 以前是寻找 ...

  5. ETL的测试

    二.ETL测试过程: 在独立验证与确认下,与任何其他测试一样,ETL也经历同样的阶段. 1)业务和需求分析并验证. 2)测试方案编写 3)从所有可用的输入条件来设计测试用例和测试场景进行测试 4)执行 ...

  6. Oracle EBS Add Responsibility to User by the Responsibility reference of Other User.

    Oracle EBS 11i Add Responsibility to User by the Responsibility reference of Other User. Warning: R1 ...

  7. api接口响应类型定义

    public class Response<T> { public ResponseStatus Status { get; set; } public string Message { ...

  8. 杭州.Net 相关大公司,希望对大家有帮助

    本人目前大四,还在实习.北京工作辞职后,打算回杭州看看.发现杭州的大公司相对北京好少啊,招.Net相关的公司就更少了... (我认为刚毕业生还是去大公司比较靠谱,一方面也是实力的体现)大学生,而且之前 ...

  9. 日笔记--C# 从数据库取表格到DataGridView---json传输

    只作为个人学习笔记. class OpData { // 创建一个和客户端通信的套接字 Socket socketwatch = null; //连接Access字符串 string strCon; ...

  10. 虚拟化 - Hyper-V

    不能和VMware.VirtualBox同时使用 网络 交换机其实就是指网卡,只不过是虚拟的 内部交换机 外部交换机