链接:P4774

前言:

交了18遍最后发现是多组数据没清空/ll


题意:

其实就是个扩中。


分析过程:

首先发现根据题目描述的选择剑的方式,每条龙对应的剑都是固定的,有查询前驱,后继(在该数不存在前驱时,最小值即为后继),和插入,删除操作,所以想到平衡树维护每条龙的剑的攻击力,记为b[i]。建议使用非旋treap,非常之好写。


根据题目描述,a[i]为每条龙生命值,p[i]为每条龙回复量。发现能够击杀这条龙的条件可以列成一个方程:

\(xb[i]-yp[i]=a[i]\)

\(x\) 为攻击次数,\(y\) 为回复次数,转化为同余方程的形式为:

\(xb[i]\equiv a[i]\pmod {p[i]}\)

所以题目就被我们转化成了一个一元 \(n\) 次的不定方程组:

\(\begin{cases}xb[1]\equiv a[1]\pmod {p[1]} \\ xb[2]\equiv a[2]\pmod {p[2]}\\ \vdots\\ xb[n]\equiv a[n]\pmod {p[n]}\end{cases}\)

求 \(x\) 的最小非负整数解。

这样的形式虽然不满足CRT和exCRT的形式,但我们可以从exCRT的思想得到启发。我们记录下前 \(m-1\) 个方程的通解 \(x=x_0+t*M\),也就是说我们已知 \(x_0\) 和 \(M\)。

对于第 \(m\) 个方程 \(xb[m]-yp[m]=a[m]\) ,将上述 \(x\) 带入,有

\((x_0+t*M)b[i]-yp[i]=a[i]\)

即 \(x_0b[i]+t*M*b[i]-yp[i]=a[i]\)

由于\(x_0,b[i],M,p[i],a[i]\) 全部都已知,所以化为

\(t*Mb[i]-y*p[i]=a[i]-x_0b[i]\)

设 \(ta=Mb[i],tb=p[i],tc=a[i]-x_0b[i]\)

就有 \(t*ta-y*tb=tc\)

可以用扩展欧几里得求解 \(t=t_0+q*\frac{tb}{\gcd(ta,tb)}\)。

如果 \(t\) 无解那显然此题就无解。

为了这里看起来简洁一些,设 \(r=\frac{tb}{\gcd(ta,tb)}\)。

则 \(t=t_0+q*r\)

发现我们不停带入化简求出了前 \(m-1\) 个方程的解 \(x=x_0+t*M\) 中 \(t\)的范围,所以再将 \(t\) 带入该式,有:

\(x=x_0+(t_0+q*r)*M\)

即 \(x=x_0+t_0*M+q*r*M\)

还看不出来吗?那就再括起来:

\(x=(x_0+t_0*M)+q*(r*M)\)

这个写法是不是和 \(x=x_0+t*M\) 有点像?没错,这就是合并了两个方程之后的解。

发现我们完全通过柿子和推导得出了合并方程的方法,只需要做一次扩展欧几里得。那么对于第一个方程怎么办呢,我们当然可以特殊处理第一个方程,求出它的解。还有另一种巧妙的办法,就是将 \(x\) 一开始的取值范围设为 \(\mathbb{Z}\),只需将 \(M\) 设为 \(1\),即 \(x=x_0+t*1\) ,这里的 \(x_0\) 对结果应该没有影响,我测试了几个不同的初值都能过,这样就不用单独处理第一个方程了。


坑1:

注意我们转化方程 \(xb[i]-yp[i]=a[i]\) 的过程是有缺陷的,根据题意,这里的 攻击次数 \(x\) 和回复次数 \(y\) 显然都应该是非负数而且有一定限制,翻译成人话就是说你砍出来的伤害至少要大于这条龙的血量。再翻译成数学语言就是:

\(\forall i\ (i\in \left [ 1,n \right ]),xb[i]\geq a[i]\)

转化不等式:\(x\geq \frac{a[i]}{b[i]}\)

所以用double类型记录最大的 \(\frac{a[i]}{b[i]}\),把最后的解处理一下即可。


坑2:

因为此题数据范围较大,long long会溢出,所以需要在各种地方取模并使用龟速乘防止溢出。由于我们记录的一直是通解,所以\(x_0\) 的值并不要求最小,只是为了避免溢出所以让 \(x_0\) 每次对 \(M\) 取模。


坑3:

就是我亲身踩了17次的注意平衡树每次会有剩下的剑还在树中,注意清空。


代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+5; int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
} //treap-------------------
#define v(x) kin[x].v
#define lc(x) kin[x].lc
#define rc(x) kin[x].rc
#define siz(x) kin[x].siz
#define rnd(x) kin[x].rnd
struct k{
int v,lc,rc,siz,rnd;
}kin[2*maxn];
int rt,cnt;
int newnode(int x){
rnd(++cnt)=rand();
siz(cnt)=1;
v(cnt)=x;
lc(cnt)=rc(cnt)=0;
return cnt;
}
void pushup(int x){
siz(x)=siz(lc(x))+siz(rc(x))+1;
}
int merge(int x,int y){
if(!x||!y)return x|y;
if(rnd(x)<rnd(y)){
rc(x)=merge(rc(x),y);
pushup(x);
return x;
}
else{
lc(y)=merge(x,lc(y));
pushup(y);
return y;
}
}
void split(int p,int k,int &x,int &y){
if(!p){x=y=0;return ;}
if(v(p)<=k){
x=p;
split(rc(p),k,rc(p),y);
pushup(p);
}
else{
y=p;
split(lc(p),k,x,lc(y));
pushup(p);
}
}
void insert(int v){
int x,y,z;
x=y=z=0;
split(rt,v,x,z);
y=newnode(v);
rt=merge(merge(x,y),z);
}
void del(int v){
int x,y,z;
x=y=z=0;
split(rt,v,x,z);
split(x,v-1,x,y);
y=merge(lc(y),rc(y));
rt=merge(merge(x,y),z);
}
int getb(int a){
int x,y;
x=y=0;
split(rt,a,x,y);
if(x){
int now=x;
while(rc(now))now=rc(now);
now=v(now);
rt=merge(x,y);
del(now);
return now;
}
else{
int now=y;
while(lc(now))now=lc(now);
now=v(now);
rt=merge(x,y);
del(now);
return now;
}
}
//treap---------------------------- int exgcd(int a,int b,int &x,int &y){
if(a<b)return exgcd(b,a,y,x);
if(a%b==0){
x=0;y=1;
return b;
}
else{
int tx,ty;
int d=exgcd(b,a%b,tx,ty);
x=ty;
y=tx-a/b*ty;
return d;
}
}
int gsc(int ta,int tb,int mod){
if(!ta||!tb)return 0;
int ans=0,f=1;
if(ta<0)ta=-ta,f*=-1;
if(tb<0)tb=-tb,f*=-1;
ta%=mod;
tb%=mod;
while(tb){
if(tb&1)ans=(ans+ta)%mod;
ta=(ta+ta)%mod;
tb>>=1;
}
return ans*f;
}
int T;
int n,m;
int a[maxn],p[maxn],q[maxn],b[maxn];
int x0,M;
signed main(){
T=read();
while(T--){
cnt=0,rt=0;
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
p[i]=read();
for(int i=1;i<=n;i++)
q[i]=read();
for(int i=1;i<=m;i++){
int temp=read();
insert(temp);
}
for(int i=1;i<=n;i++){
b[i]=getb(a[i]);
insert(q[i]);
}
x0=0,M=1;
int ta,tb,tc,t,y,d,flag=1;
double mx=0;
for(int i=1;i<=n;i++){
ta=M*b[i],tb=p[i],tc=a[i]-x0*b[i];
d=exgcd(ta,tb,t,y);
if(tc%d!=0){
printf("-1\n");
flag=0;
break;
}
ta/=d,tb/=d,tc/=d;
t=(t%tb+tb)%tb;
x0+=gsc(gsc(tc,t,M*tb),M,M*tb);
M*=tb;
x0=(x0%M+M)%M;
if(double(a[i])/b[i]>mx)
mx=double(a[i])/b[i];
}
while(x0<mx)x0+=M;
if(flag)
printf("%lld\n",x0);
}
return 0;
}

题外话:

做完感觉自己就是屠龙勇士,另外感觉这道题很好的揭示了平衡树这一工具人的作用

洛谷 P4774 [NOI2018] 屠龙勇士的更多相关文章

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

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

  2. (伪)再扩展中国剩余定理(洛谷P4774 [NOI2018]屠龙勇士)(中国剩余定理,扩展欧几里德,multiset)

    前言 我们熟知的中国剩余定理,在使用条件上其实是很苛刻的,要求模线性方程组\(x\equiv c(\mod m)\)的模数两两互质. 于是就有了扩展中国剩余定理,其实现方法大概是通过扩展欧几里德把两个 ...

  3. 洛谷P4774 [NOI2018]屠龙勇士 [扩欧,中国剩余定理]

    传送门 思路 首先可以发现打每条龙的攻击值显然是可以提前算出来的,拿multiset模拟一下即可. 一般情况 可以搞出这么一些式子: \[ atk_i\times x=a_i(\text{mod}\ ...

  4. P4774 [NOI2018]屠龙勇士

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

  5. luogu P4774 [NOI2018]屠龙勇士

    传送门 这题真的是送温暖啊qwq,而且最重要的是yyb巨佬在Day2前几天正好学了crt,还写了博客 然而我都没仔细看,结果我就同步赛打铁了QAQ 我们可以先根据题意,使用set维护,求出每次的攻击力 ...

  6. BZOJ5418[Noi2018]屠龙勇士——exgcd+扩展CRT+set

    题目链接: [Noi2018]屠龙勇士 题目大意:有$n$条龙和初始$m$个武器,每个武器有一个攻击力$t_{i}$,每条龙有一个初始血量$a_{i}$和一个回复值$p_{i}$(即只要血量为负数就一 ...

  7. BZOJ_5418_[Noi2018]屠龙勇士_exgcd+excrt

    BZOJ_5418_[Noi2018]屠龙勇士_exgcd+excrt Description www.lydsy.com/JudgeOnline/upload/noi2018day2.pdf 每次用 ...

  8. uoj396 [NOI2018]屠龙勇士

    [NOI2018]屠龙勇士 描述 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照编号 1∼n 顺序杀掉 n 条巨龙,每条巨龙拥有一个初始的生命值 ai .同时每条巨龙拥有恢复能 ...

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

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

随机推荐

  1. Emit优化反射(属性的设置与获取)

    在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过Emit技术优化反射来提高获取和设置属性值的效率 一.实现代码: /// <summary> /// 设置器委托 /// < ...

  2. 洛谷P1582——倒水(进制,数学)

    https://www.luogu.org/problem/show?pid=1582 题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了 ...

  3. ecshop后台设置模板的地方显示自己新建模板的操作界面

    我建立了一个叫test.dwt文件怎样在后台设置模板里面出现呢.1首先找到ecshop目录下的languages\zh_cn\admin/template.php 这个php文件 当然如果这只是简体中 ...

  4. 安装VM-TOOLS,解压tar包时提示目录磁盘空间不足

    在虚拟机里安装了ubuntu-18.04.4-desktop-amd64,安装VM-TOOLS,解压tar包时提示目录磁盘空间不足. 解决方法一: 打开terminal,输入:sudo apt ins ...

  5. jmeter压测学习12-设置持续压测时间(调度器的使用)

    前言 使用jmeter 做压测的时候,希望对一个接口持续压测 10 分钟或者半小时,可以使用调度器设置持续压测时间. 设置样本总数 压测方式有2种,一种是设置线程组和循环次数,这样可以设置一个样本总数 ...

  6. MyBatis Plus 批量数据插入功能,yyds!

    最近 Review 小伙伴代码的时候,发现了一个小小的问题,小伙伴竟然在 for 循环中进行了 insert (插入)数据库的操作,这就会导致每次循环时都会进行连接.插入.断开连接的操作,从而导致一定 ...

  7. ASP.NET Core 5.0 中读取Request中Body信息

    ASP.NET Core 5.0 中读取Request中Body信息 记录一下如何读取Request中Body信息 public class ValuesController : Controller ...

  8. 现在有一个长度20的SET,其中每个对象的内容是随机生成的字符串,请写出遍历删除LIST里面字符串含"2"的对象的代码。

    现在有一个长度20的SET,其中每个对象的内容是随机生成的字符串,请写出遍历删除LIST里面字符串含"2"的对象的代码. public class RemoveTwo { //le ...

  9. css新增属性之边框

    css3新增属性 边框属性 背景属性 文字属性 颜色属性 边框属性 属性 说明 border-radius 设置边框圆角 border-image 设置图像边框 border-shadow 设置边框阴 ...

  10. cmd下载慢

    是网络的原因,加一个镜像服务器 pip install *** -i https://pypi.tuna.tsinghua.edu.cn/simple