洛谷P4774 BZOJ5418 LOJ2721 [NOI2018]屠龙勇士(扩展中国剩余定理)
题目链接:
题目大意:这么长的题面,就饶了我吧emmm
这题第一眼看上去没法列出同余方程组。为什么?好像不知道用哪把剑杀哪条龙……
仔细一看,要按顺序杀龙,所以获得的剑出现的顺序也是固定的。
那么如果能把所有龙杀死,就能模拟出哪把剑杀那条龙了。
(以下设所有除 $n,m$ 外的数的最大值为 $v$)
$O(nm)$?
不,发现这里用剑的限制实际上是给出一个上界,来用lower_bound的。
插入也不要太暴力。我们想到什么?手写平衡树multiset!
这一部分复杂度是 $O(n\log m)$。
接下来就成了一个同余方程组:$atk_ix\equiv hp_i(\operatorname{mod}\ rec_i)$。
($atk_i$ 表示攻击第 $i$ 条龙的攻击力,$hp_i$ 表示第 $i$ 条龙的血量,$rec_i$ 表示第 $i$ 条龙的恢复能力)
但是好像没那么简单!有一些神奇的情况……要特判!
在考场上的话我肯定想不到特判任何东西
首先大家应该都知道,$x\equiv a_i(\operatorname{mod}\ b_i)$ 等价于 $x\equiv a_i\ \operatorname{mod}\ b_i(\operatorname{mod}\ b_i)$。
但是在这题中不行!你总不能把一头龙的血量凭空减少吧!
所以 $hp_i>rec_i$ 时(题目描述中的特性1不满足时)怎么办?
我们发现不满足特性1的点都满足 $rec_i=1$……也就是只要把他的血量打到小于0就赢了!
此时答案是 $\max\limits_{1\le i\le n}(\lceil\frac{hp_i}{atk_i}\rceil)$。
另外要注意 $x\ge\max(\lceil\dfrac{hp_i}{atk_i}\rceil)$。
至此所有特判结束。
我们一般的EXCRT同余方程组的形式是 $x\equiv a_i(\operatorname{mod}\ b_i)$。
但是这里有讨厌的 $atk_i$!更讨厌的是可能没有逆元,不能直接除过去!
我们来看看如何变形:
$atk_ix\equiv hp_i(\operatorname{mod}\ rec_i)$
$atk_ix+rec_iy=hp_i$
此时可以EXGCD解出 $x$ 的最小正整数解 $x_0$。
根据某定理(什么定理来着?)可得通解为 $x=x_0+\frac{rec_i}{\gcd(atk_i,rec_i)}k(k\in N^+)$。
于是就变成了 $x\equiv x_0(\operatorname{mod}\ \frac{rec_i}{\gcd{atk_i},rec_i})$。
这一部分复杂度为 $O(n\log v)$。
接下来就是裸的EXCRT了!
这一部分复杂度为 $O(n\log v)$。
等一下,还有一句提示没看到:
你所用到的中间结果可能很大,注意保存中间结果的变量类型。
突然慌张
冷静分析一下,我们在各种算法中模数都有可能超过int范围,要是一乘……
那……只能上龟速乘了。时间复杂度是没变,但是常数的话……
幸好不是wys的题,不然时限就是1s了
好吧,都说完了,上代码吧。(之前因为数据水没有注意 $x\ge\max(\lceil\dfrac{hp_i}{atk_i}\rceil)$)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=;
multiset<ll> mts; //模拟拿剑
int t,n,m;
bool spec,exist,same;
ll hp[maxn],rec[maxn],a[maxn],b[maxn]; //a,b表示最后方程组是x=a_i(mod\ b_i)
int award[maxn],atk[maxn]; //award是奖励的剑
ll qmul(ll a,ll b,ll mod){ //*速乘
ll ans=;
for(;b;b>>=,a=(a+a)%mod) if(b&) ans=(ans+a)%mod;
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y){ //模板
if(!b){x=;y=;return a;}
ll d=exgcd(b,a%b,y,x);y-=a/b*x;return d;
}
ll gcd(ll a,ll b){ //(不要问我为什么有这个)
if(!b) return a;
return gcd(b,a%b);
}
int main(){
scanf("%d",&t);
while(t--){
spec=false;same=exist=true; //spec是rec=1,same是hp=rec,exist是有没有解
mts.clear();
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%lld",hp+i);
for(int i=;i<=n;i++){scanf("%lld",rec+i);if(rec[i]<hp[i]) spec=true;} //rec<hp?
for(int i=;i<=n;i++) scanf("%d",award+i);
for(int i=;i<=m;i++){
int x;
scanf("%d",&x);
mts.insert(x); //全部进去
}
for(int i=;i<=n;i++){
multiset<ll>::iterator it;
if(hp[i]<*mts.begin()) it=mts.begin(); //如果没有比血量小的剑,则用第一把(最小的)
else it=mts.upper_bound(hp[i]),it--; //否则用第一个大于它的-1(即最后一个小于等于它的)
atk[i]=*it;
mts.erase(it);
mts.insert(award[i]); //拿走再选
}
if(spec){ //特判hp>rec
ll ans=;
for(int i=;i<=n;i++) ans=max(ans,ll(ceil(1.0*hp[i]/atk[i])));
printf("%lld\n",ans);
continue;
}
for(int i=;i<=n;i++){
if(!atk[i]){puts("-1");exist=false;break;} //无法攻击?无解
if(hp[i]!=rec[i]) same=false; //hp=rec?
ll x,y,d=exgcd(atk[i],rec[i],x,y); //解x0
if(hp[i]%d){puts("-1");exist=false;break;} //无解
x=(x+rec[i])%rec[i];b[i]=rec[i]/d;a[i]=qmul(x,hp[i]/d,b[i]); //真的x0推出b=rec/gcd(atk,rec),a=x0
}
if(same){ //特判hp=rec
ll ans=ll(ceil(1.0*hp[]/atk[]));
for(int i=;i<=n;i++){
ll x=ceil(1.0*hp[i]/atk[i]),d=gcd(ans,x);
ans=ans/d*x;
}
printf("%lld\n",ans);continue;
}
if(!exist) continue;
ll ans=a[],mod=b[]; //开始EXCRT(以下模板,不解释,可以去我的另一个博客看)
for(int i=;i<=n;i++){
ll x,y,d=exgcd(mod,b[i],x,y),r=((a[i]-ans)%b[i]+b[i])%b[i],tmp=mod/d*b[i];
if(r%d){puts("-1");exist=false;break;}
x=(x+b[i])%b[i];x=qmul(x,r/d,b[i]);
ans=(qmul(mod,x,tmp)+ans)%tmp;
mod=tmp;
}
if(!exist) continue;
printf("%lld\n",ans); //终于没了
}
}
NOI2018D2T1_dragon(EXCRT)
终于啊……
洛谷P4774 BZOJ5418 LOJ2721 [NOI2018]屠龙勇士(扩展中国剩余定理)的更多相关文章
- 洛谷 P4774 / loj 2721 [NOI2018] 屠龙勇士 题解【同余】【exgcd】【CRT】
推导过程存在漏洞+exCRT板子没打熟于是期望得分÷实际得分=∞? 题目描述 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照编号 \(1\sim n\) 顺序杀掉 \(n\ ...
- LOJ.2721.[NOI2018]屠龙勇士(扩展CRT 扩展欧几里得)
题目链接 LOJ 洛谷 rank前3无压力(话说rank1特判打表有意思么) \(x*atk[i] - y*p[i] = hp[i]\) 对于每条龙可以求一个满足条件的\(x_0\),然后得到其通解\ ...
- LOJ2721 [NOI2018] 屠龙勇士 【扩展中国剩余定理】
好久没写了,写一篇凑个数. 题目分析: 这题不难想,讲一下中国剩余定理怎么扩展. 考虑$$\left\{\begin{matrix}x \equiv a\pmod{b}\\ x \equiv c\pm ...
- 扩展中国剩余定理学习笔记+模板(洛谷P4777)
题目链接: 洛谷 题目大意:求同余方程组 $x\equiv b_i(mod\ a_i)$ 的最小正整数解. $1\leq n\leq 10^5,1\leq a_i\leq 10^{12},0\leq ...
- [洛谷P4774] [NOI2018]屠龙勇士
洛谷题目链接:[NOI2018]屠龙勇士 因为markdown复制过来有点炸格式,所以看题目请戳上面. 题解: 因为杀死一条龙的条件是在攻击\(x\)次,龙恢复\(y\)次血量\((y\in N^{* ...
- (伪)再扩展中国剩余定理(洛谷P4774 [NOI2018]屠龙勇士)(中国剩余定理,扩展欧几里德,multiset)
前言 我们熟知的中国剩余定理,在使用条件上其实是很苛刻的,要求模线性方程组\(x\equiv c(\mod m)\)的模数两两互质. 于是就有了扩展中国剩余定理,其实现方法大概是通过扩展欧几里德把两个 ...
- P4774 [NOI2018]屠龙勇士
P4774 [NOI2018]屠龙勇士 先平衡树跑出打每条龙的atk t[] 然后每条龙有\(xt \equiv a[i](\text{mod }p[i])\) 就是\(xt+kp[i]=a[i]\) ...
- BZOJ5418[Noi2018]屠龙勇士——exgcd+扩展CRT+set
题目链接: [Noi2018]屠龙勇士 题目大意:有$n$条龙和初始$m$个武器,每个武器有一个攻击力$t_{i}$,每条龙有一个初始血量$a_{i}$和一个回复值$p_{i}$(即只要血量为负数就一 ...
- BZOJ_5418_[Noi2018]屠龙勇士_exgcd+excrt
BZOJ_5418_[Noi2018]屠龙勇士_exgcd+excrt Description www.lydsy.com/JudgeOnline/upload/noi2018day2.pdf 每次用 ...
随机推荐
- C++自学成长之路(第一篇)
今天开始我将开启C++自学成长之路,今天是第一天,在以前就一直在网上查找关于c++的资料,想买一本好一点的,权威一点的资料书,通过努力查找,我选择了c++ primer,在网上这本书的好评如潮.更多的 ...
- POJ2531&&1416&&2676&&1129
搜索专题的最后一块了,也告别了这些老的东西了 接下来就是些全新的内容了啊! 这次的标签是简单搜索技巧和剪枝,也就是优化爆搜 当然,像Dancing links这样的玄学操作还是没有的 2531 题意: ...
- mfc CAnimateCtrl
知识点: CAnimateCtrl成员函数 播放avi动画 一. CAnimateCtrl成员函数 Autoplay; CAnimateCtrl ::成员函数 Open 打开avi视频 Play 播放 ...
- Macaca之Android原理浅析
经过研究macaca的android模块源码,原理主要由以下三块构成 一.uiautomator TODO 二.nanohttp TODO 二.adb forward TODO
- [Mark]Tomcat/IIS 更改 HTTP 侦听端口
目的: IIS HTTP 侦听端口改为 8088 Tomcat HTTP 侦听端口改为 80 环境: Windows Server 2012 R2 IIS8.5 (默认端口是 80) Tomcat8. ...
- SpringBoot日记——缓存的使用
SpringBoot核心技术的东西基本上都有介绍过了,接下来,进阶点~来说说缓存吧~ 缓存这个词不少同学应该不会很陌生.而我们这里主要使用的就是Redis. 客户端第一次请求的时候是从库里拿出我们需要 ...
- CryptoZombies学习笔记——Lesson2
第二课是僵尸猎食,将把app变得更像一个游戏,添加多人模式,建立更多创造僵尸的方法. chapter1 依然是简介 chapter2:映射和地址 映射相当于一个索引,指向不同地址,不同地址存储的数据不 ...
- 1090. Highest Price in Supply Chain (25)-dfs求层数
给出一棵树,在树根出货物的价格为p,然后每往下一层,价格增加r%,求所有叶子节点中的最高价格,以及该层叶子结点个数. #include <iostream> #include <cs ...
- Linux内核分析——第四周学习笔记
扒开系统调用的三层皮[上] 前言:以下笔记除了一些讲解视频中的概念记录,图示.图示中的补充文字.总结.分析.小结部分均是个人理解.如有错误观点,请多指教! 补充:[系统调用的参数传递方法]视频中讲解简 ...
- #Linux第四周学习总结——扒开系统调用的三层皮(上)
Linux第四周学习总结--扒开系统调用的三层皮(上) 一.用户态.内核态和中断 系统调用通过库函数. 1.用户态和内核态 区分(不同的指令执行级别): 用户态:在相应的低执行状态下,代码的掌控范围受 ...