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\) ...
随机推荐
- assign()与create()的区别
Q:assign()与create()的区别? A:let obj = Object.assign(targetObj, -sourceObj) 作用:将一个或多个源对象自身的可枚举属性与目标对象的属 ...
- Spring 事务回滚机制详解
1:事务原理 1.2:aop/动态代理 类路径:org/springframework/aop/framework/CglibAopProxy.java ReflectiveMethodInvocat ...
- Servlet学习笔记(二)之Servlet路径映射配置、Servlet接口、ServletConfig、ServletContext
Servlet路径映射配置 要使Servlet对象正常的运行,需要进行适当的配置,以告诉Web容器哪个请求调用哪个Servlet对象处理,对Servlet起到一个注册的作用.Servlet的配置信息包 ...
- Shiro02
Shiro认证 Pom依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>s ...
- Struts2 的 OGNL
ONGL简介: OGNL 的全称是对象图导航语言( Object-Graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可以通过某种表达式语法,存 ...
- C# 爬虫框架实现 流程_各个类开发
目录链接:C# 爬虫框架实现 概述 对比通用爬虫结构,我将自己写的爬虫分为五个类实现: Spider主类:负责设置爬虫的各项属性 Scheduler类:负责提供URL到下载类,接收URL并做去重 Do ...
- WEB漏洞——RCE
RCE(remote command/code execute)远程命令/代码执行漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统. RCE漏洞 应用程序有时需要调用一 ...
- ES6:使用解构赋值仅用一行定义多个相同的数组,且指向堆不同(解构赋值)
在开发过程中我们经常要用到一些临时变量对数据进行一些特殊处理,由于良好的编码习惯要在临时变量用完后释放内存,所以当临时变量数量较多时,整体代码会变得冗余. let a = [] let b = [] ...
- [第十三篇]——Docker Compose之Spring Cloud直播商城 b2b2c电子商务技术总结
Docker Compose Compose 简介 Compose 是用于定义和运行多容器 Docker 应用程序的工具.通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务.然 ...
- 解决国内npm安装太慢的方法,又不能FQ情况下,使用淘宝镜像教程
安装npm及cnpm(Windows) [工具官网] 因为国内上网下载组件太慢,淘宝给我们提供了镜像源,,但是我不是建意FQ上网.条件有限的可以使用下面的方法安装CNPM,原文转自网络,正好自己需要也 ...