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\) ...
随机推荐
- 解析ThreadPoolExecutor类是如何保证线程池正确运行的
摘要:对于线程池的核心类ThreadPoolExecutor来说,有哪些重要的属性和内部类为线程池的正确运行提供重要的保障呢? 本文分享自华为云社区<[高并发]通过源码深度解析ThreadPoo ...
- rabbitMq接收实体
- 闭包 panic recover
闭包=函数+外层变量的引用 recover必须搭配defer使用 defer一定要在可能引发panic的语句之前定义
- x和y为正整数变量,求满足 x+y | xy 的通解。
x和y为正整数变量,求满足 x+y | xy 的通解. 解:由题设可知存在正整数t满足t(x+y)=xy. 设m=(x,y),则存在正整数u和v满足: x=mu, y=mv, (u,v)=1. 于是有 ...
- 一个double free相关问题的澄清
引言 前一阵定位 Oracle 的 OCI 接口相关的一个内存释放问题,在网上看到了链接如下的这篇文章: 一个C++bug引入的许多知识 看到后面说 vector 里的两个单元里的内部成员指针地址是一 ...
- Java - 注释、标识符、关键字
背景 要开始磕 Java 了,虽然以前学过用过,但是差不多忘光光了... 现在直接搬狂神的视频素材,不再自己总结,要学的东西太多了... 注释 单行注释 // 多行注释 /* */ 文档注释 /** ...
- 【Python从入门到精通】(二十五)Python多进程的使用
您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. 本篇重点介绍Python多进程的使用,读者朋友们可以将多进程和多线程两者做一个对比学习. 干货满满,建议收藏,需要用到时常看看. 小伙伴们如有问题 ...
- L2TP协议简介
传送门:L2TP代码实现 1. L2TP 概述 L2TP(Layer 2 Tunneling Protocol,二层隧道协议)是 VPDN(Virtual Private Dial-up Networ ...
- C# List集合类常用操作:三、查找
List集合查询数据 List<Employees> employees = new List<Employees>(); employees.Add(new Employee ...
- Spring-图解