推导过程存在漏洞+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. ORACLE DBLINK 使用

    CREATE PUBLIC DATABASE LINK MYDBLINK CONNECT TO RAMS IDENTIFIED BY RAMS USING '(DESCRIPTION =(ADDRES ...

  2. kaggle-泰坦尼克号Titanic-2

    下面我们再来看看各种舱级别情况下各性别的获救情况 fig = plt.figure() fig.set(alpha=0.5) plt.title(u"根据舱等级和性别的获救情况", ...

  3. 整理悬浮在列表中a元素时改变a元素上下边框颜色的问题。

    整理一下当悬浮在a元素上时a的上下边颜色改变,并且里面的内容不会移动,下面是PSD图效果区域: 刚开始我先给A元素加了上下边框和颜色,利用a:hover改变a元素上下的边框颜色,但是第一个a元素的下边 ...

  4. 如何在Windows环境下安装Linux系统虚拟机

    如何在Windows环境下安装Linux系统虚拟机 本篇经验写给想要入门学习C语言的小白们.Windows系统因为使用窗口图形化,操作简单,功能多样,所以我们在Windows环境下可以做到很多,但想要 ...

  5. Baidu Map开发示例

    1.获取SHA1码 在Eclipse中点击“Windows”----->“Preferences” ----->“Android” ----->“Build”如下图: 打开“Win+ ...

  6. UVALive - 6434 —(思维题)

    题意:给出了你由n个数组成的序列,让你将这个序列分为成m个集合,使得每一个集合的最大值减最小值的差相加最小.(如果某集合只有一个数字,则最大值减最小值为0) . 思路:首先我们不难想到,最优的分配方法 ...

  7. 基于jCOM搭建Java-微软信息桥梁(下)

    第一部分析了BEA提供的Java/COM互操作解决方案—jCOM的实现原理:本文是第二部分,比较全面地分析了Weblogic Server的jCOM实现技术之后,通过一个具体实例来说明了jCOM的具体 ...

  8. PostgreSQL 表空间

    PostgreSQL 表空间 一 介绍使用表空间可以将不同的表放到不同的存储介质或不同的文件系统下,实际上是为表指定一个存储的目录.创建数据库,表,索引时可以指定表空间,将数据库,表,索引放到指定的目 ...

  9. 使用Eclipse切换TFS工作区

    这个问题首先牵涉到两个概念: - Eclipse的工作区:Eclipse的工作区是运行Eclipse时需要连接的本地代码空间,默认情况下,在Eclipse中创建的项目都保存在Eclipse的工作区中 ...

  10. SQL Server数据类型总结

    1.char char [(n)]存储固定长度的非Unicode字符串数据.n定义字符串长度,并且必须是1到8,000之间的值.存储大小为n个字节. 2.varchar varchar [(n | m ...