NOI2018屠龙勇士(扩展CRT + splay(multiset))
QWQ 一到假期就颓废 哎
今年新鲜出炉的NOI题,QwQ同步赛的时候写的,后来交了一发洛谷,竟然过了
首先 根据题目,我们很容易得到,假设对应每一条龙的剑的攻击力是\(atk\)的话
\]
\]
QwQ一看到这个式子,就想到了扩展crt求解。
不过我一开始的想法是,根据扩欧,求$a_i-x\times atk + k *p_i = 0 \(中的每一个\)x$的通解表达式,然后把它写成同余的形式,最后再用扩展CRT合并
但是因为有点麻烦 所以没写
这里提供\(was_n\)爷的做法
就是通过求逆元,直接把\(atk\)弄到等式的右边
只有当一个数和模数互质,他们才会有逆元
我们知道$$a_i-x\times atk + k *p_i = 0 $$
所以$$a_i= x\times atk + k *p_i$$
然后这个方程有解的条件是\(a_i | gcd(atk,p_i)\)
那么我们先把等式两边同时除以\(gcd(atk,p_i)\) ,再写成同余式子的形式$$x\times \frac{atk}{gcd} = \frac{a_i}{gcd} \pmod {\frac{p_i}{gcd}}$$
此时 $ \frac{atk}{gcd}\(和\)\frac{p_i}{gcd}$是互质的,所以一定存在逆元,然后就可以化成扩展crt的形式,之后求解就行
至于每一次确定\(atk\)的过程,只需要一颗平衡树就行,不过要注意,可能会存在重复的元素,所以理论上不能用\(set\)
哦对!一个重要的事情!
在crt和一开始乘逆元的过程中,会爆long long,所以需要快速乘来进行乘法!这里一定要注意!
以后遇到这种题,要想到快速乘!
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e5+1e2;
ll lif[maxn],p[maxn],a[maxn],m[maxn];
ll atk[maxn];
ll sz[maxn],ch[maxn][4],fa[maxn];
ll cnt[maxn],size=2,n,mm,root,t;
ll val[maxn];
ll jiangli[maxn];
bool flag=true;
ll mul(ll i,ll j,ll p)
{
ll ans=0;
while (j){
if (j&1) ans=(ans+i)%p;
i=(i+i)%p;
j>>=1;
}
return ans;
}
ll son (ll x)
{
if (x==ch[fa[x]][0]) return 0;
else return 1;
}
void update(ll x)
{
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
}
void rotate(ll x)
{
ll y=fa[x],z=fa[y];
ll b=son(x),c=son(y);
ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
}
void splay(ll x,ll p)
{
while (fa[x]!=p)
{
ll y=fa[x],z=fa[y];
if (z==p) rotate(x);
else
if (son(x)==son(y))
{
rotate(y);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
if (fa[x]==0) root=x;
}
ll find_qq(ll x)
{
ll now = root,num=0;
while (now)
{
if (val[now]<x)
{
num=now;
now=ch[now][1];
}
else
now=ch[now][0];
}
return num;
}
ll find_hj(ll x)
{
ll now = root,num=0;
while (now)
{
if (val[now]>x)
{
num=now;
now=ch[now][0];
}
else
now=ch[now][1];
}
return num;
}
void insert(ll x)
{
ll qq=find_qq(x);
ll hj=find_hj(x);
splay(qq,0);
splay(hj,qq);
ll y=ch[hj][0];
if (cnt[y])
cnt[y]++,update(y);
else
{
size++;
fa[size]=hj;
cnt[size]=1;
val[size]=x;
sz[size]=1;
ch[hj][0]=size;
splay(size,0);
}
}
void delet(ll x)
{
ll qq=find_qq(x);
ll hj=find_hj(x);
splay(qq,0);
splay(hj,qq);
ll y=ch[hj][0];
if (cnt[y]>1)
cnt[y]--,update(y);
else
{
fa[y]=0;
cnt[y]=0;
val[y]=0;
sz[y]=0;
ch[hj][0]=0;
}
}
ll gcd(ll a,ll b)
{
if (b==0) return a;
else return gcd(b,a%b);
}
ll exgcd(ll &x,ll &y,ll a,ll b)
{
if (b==0)
{
x=1;
y=0;
return a;
}
ll cnt = exgcd(x,y,b,a%b);
ll tmp = x;
x=y;
y=tmp-a/b*y;
return cnt;
}
void init()
{
memset(ch,0,sizeof(ch));
memset(sz,0,sizeof(sz));
memset(fa,0,sizeof(fa));
memset(val,0,sizeof(val));
memset(a,0,sizeof(a));
memset(m,0,sizeof(m));
val[1]=1e18;
val[2]=-1e18;
fa[2]=1;
ch[1][0]=2;
root=1;
size=2;
flag=true;
}
ll niyuan(ll num,ll p)
{
ll ymh,szh;
exgcd(ymh,szh,num,p);
ymh=(ymh%p+p)%p;
return ymh;
}
ll count(ll x)
{
ll hj=find_qq(x+1);
if (val[hj]==-1e18){
ll ii = val[find_hj(val[hj])];
delet(ii);
return ii;
}
else
{
ll ii = val[hj];
delet(ii);
return ii;
}
}
void solve1()
{
for (int i=1;i<=n;i++)
{
ll tmp = count(lif[i]);
//cout<<tmp<<endl;
ll gcd1=gcd(tmp,p[i]);
// cout<<gcd1<<endl;
m[i]=p[i]/gcd1;
if (lif[i]%gcd1!=0) flag=false;
if (!flag) return;
lif[i]=lif[i]/gcd1;
a[i]=mul(lif[i],niyuan(tmp/gcd1,m[i]),m[i]);
insert(jiangli[i]);
}
}
long long solve()
{
ll x0=0,M=0;
x0=a[1];
M=m[1];
long long x=0,y=0;
for (int i=2;i<=n;i++)
{
ll gcd1=exgcd(x,y,M,m[i]);
if ((a[i]-x0)%gcd1!=0) flag=false;
if (!flag) return -1;
long long tmp = m[i]/gcd1;
ll yyy=(a[i]-x0)/gcd1;
yyy%=tmp;
if (yyy<=0) yyy+=tmp;
x=(x%tmp+tmp)%tmp;
x=mul(x,yyy,tmp);
ll ppp = M;
M=M/gcd1*m[i];
ppp=(ppp%M+M)%M;
x0=(mul(x,ppp,M)+x0%M)%M;
}
x0=(x0+M)%M;
if (x0==0) x0+=M;
return x0;
}
void solve3()
{
//cout<<"gg"<<endl;
ll ans=-1e9;
for (int i=1;i<=n;i++)
{
ll tmp = count(lif[i]);
ll cnt = lif[i]/tmp;
lif[i]=lif[i]%tmp;
if (lif[i]>0) cnt++;
ans=max(ans,cnt);
insert(jiangli[i]);
}
cout<<ans<<endl;
}
int main()
{
//freopen("dragon.in","r",stdin);
//freopen("dragon.out","w",stdout);
cin>>t;
while (t--)
{
init();
n=read(),mm=read();
int now = 0;
for (int i=1;i<=n;i++) lif[i]=read();
for (int i=1;i<=n;i++)
{
p[i]=read();
if (p[i]==1) now++;
}
for (int i=1;i<=n;i++) jiangli[i]=read();
for (int i=1;i<=mm;i++) atk[i]=read(),insert(atk[i]);
if (now==n) {
solve3();
continue;
}
solve1();
if (!flag) {
cout<<-1<<endl;
continue;
}
//cout<<"hhh"<<endl;
//for (int i=1;i<=n;i++) cout<<a[i]<<endl;
ll ans=solve();
if (!flag) {
cout<<-1<<endl;
continue;
}
cout<<ans<<endl;
}
return 0;
}
NOI2018屠龙勇士(扩展CRT + splay(multiset))的更多相关文章
- LOJ.2721.[NOI2018]屠龙勇士(扩展CRT 扩展欧几里得)
题目链接 LOJ 洛谷 rank前3无压力(话说rank1特判打表有意思么) \(x*atk[i] - y*p[i] = hp[i]\) 对于每条龙可以求一个满足条件的\(x_0\),然后得到其通解\ ...
- 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 每次用 ...
- P4774 [NOI2018]屠龙勇士
P4774 [NOI2018]屠龙勇士 先平衡树跑出打每条龙的atk t[] 然后每条龙有\(xt \equiv a[i](\text{mod }p[i])\) 就是\(xt+kp[i]=a[i]\) ...
- uoj396 [NOI2018]屠龙勇士
[NOI2018]屠龙勇士 描述 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照编号 1∼n 顺序杀掉 n 条巨龙,每条巨龙拥有一个初始的生命值 ai .同时每条巨龙拥有恢复能 ...
- [洛谷P4774] [NOI2018]屠龙勇士
洛谷题目链接:[NOI2018]屠龙勇士 因为markdown复制过来有点炸格式,所以看题目请戳上面. 题解: 因为杀死一条龙的条件是在攻击\(x\)次,龙恢复\(y\)次血量\((y\in N^{* ...
- LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理
题目:https://loj.ac/problem/2721 1.注意别一输入 p[ i ] 就 a[ i ] %= p[ i ] ,因为在 multiset 里找的时候还需要真实值. 2.注意用 m ...
- 洛谷 P4774 [NOI2018] 屠龙勇士
链接:P4774 前言: 交了18遍最后发现是多组数据没清空/ll 题意: 其实就是个扩中. 分析过程: 首先发现根据题目描述的选择剑的方式,每条龙对应的剑都是固定的,有查询前驱,后继(在该数不存在前 ...
- 【刷题】BZOJ 5418 [Noi2018]屠龙勇士
www.lydsy.com/JudgeOnline/upload/noi2018day2.pdf Solution 将攻击的式子列出来,\(atk \times x-p \times y=a_i\) ...
随机推荐
- Mysql You can't specify target table 'newsalrecord' for update in FROM clause
这个问题是不能先select出同一表中的某些值,再update这个表(在同一语句中),即不能依据某字段值做判断再来更新某字段的值.解决办法就是建立个临时的表.
- Ansible部署及配置介绍
原文转自:https://www.cnblogs.com/itzgr/p/10233932.html作者:木二 目录 一 Ansible的安装部署 1.1 PIP方式 1.2 YUM方式 二 Ansi ...
- 简单三分钟,本地搭建 k8s
使用 minikube 在本地搭建 k8s 已经比以前要简单很多了.本文,我们通过简短的三分钟来重现一下在本地搭建 k8s 实验环境的步骤. Newbe.Claptrap 是一个用于轻松应对并发问题的 ...
- vue-cli坑比系列
Error loading saved preferences: ~/.vuerc may be corrupted or have syntax errors. Please fix/delete ...
- GoLang设计模式06 - 对象池模式
这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...
- Intel® QAT 加速卡之数据面流程(图)
QAT数据面流程 sessionSetupData数据结构 pOpData数据结构
- 知乎大佬图文并茂的epoll讲解,看不懂的去砍他
select.poll.epoll的文章很多,自己也看过不少经典好文.不过第一次看到讲的如此通俗易懂.又图文并茂的.因此拿来分享下,供后续翻看学习. 原文链接:https://zhuanlan.zhi ...
- NAT-T下的端口浮动
1. IKE端口浮动 IPsec在隧道建立第一第二阶段主要进行加密方式.加密策略等信息的协商,这部分功能是通过IKE协议来实现的. IKE协议默认端口为500,但是如果IPsec隧道传输路径上存在NA ...
- (8)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Spring Cloud Eureka是什么?
Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件的一部分,基于 Netflix Eureka 做了二次封装,主要负责实现微服务架构中的服务治理功能. ...
- Brute Force暴力破解
Low 服务器只是验证了参数Login是否被设置,没有任何的防爆破机制,且对参数username.password没有做任何过滤,存在明显的sql注入漏洞. 方法一:bp爆破 直接对爆破密码得到pas ...