QWQ 一到假期就颓废 哎

今年新鲜出炉的NOI题,QwQ同步赛的时候写的,后来交了一发洛谷,竟然过了

首先 根据题目,我们很容易得到,假设对应每一条龙的剑的攻击力是\(atk\)的话

\[a_i-x\times atk + k *p_i = 0
\]
\[x\times atk = a_i \pmod {p_i}
\]

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))的更多相关文章

  1. LOJ.2721.[NOI2018]屠龙勇士(扩展CRT 扩展欧几里得)

    题目链接 LOJ 洛谷 rank前3无压力(话说rank1特判打表有意思么) \(x*atk[i] - y*p[i] = hp[i]\) 对于每条龙可以求一个满足条件的\(x_0\),然后得到其通解\ ...

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

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

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

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

  4. P4774 [NOI2018]屠龙勇士

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

  5. uoj396 [NOI2018]屠龙勇士

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

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

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

  7. LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理

    题目:https://loj.ac/problem/2721 1.注意别一输入 p[ i ] 就 a[ i ] %= p[ i ] ,因为在 multiset 里找的时候还需要真实值. 2.注意用 m ...

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

    链接:P4774 前言: 交了18遍最后发现是多组数据没清空/ll 题意: 其实就是个扩中. 分析过程: 首先发现根据题目描述的选择剑的方式,每条龙对应的剑都是固定的,有查询前驱,后继(在该数不存在前 ...

  9. 【刷题】BZOJ 5418 [Noi2018]屠龙勇士

    www.lydsy.com/JudgeOnline/upload/noi2018day2.pdf Solution 将攻击的式子列出来,\(atk \times x-p \times y=a_i\) ...

随机推荐

  1. Node.js开发博客系统

    数据库设计 用户表: id phone password nickname head_img personal_sign level_id create_time update_time is_del ...

  2. 记一次《C语言踩内存》问题定位有感

    踩内存问题,个人认为算是比较容易出现但是有很难定位的问题,被踩者轻者功能瘫痪,重者一命呜呼,直接诱发死机.产生踩内存的的原因也比较多样,比较典型的有如下几种: 数组越界访问 字符串越界操作 直接操作野 ...

  3. 第二课:启动 GDB 调试

    使用 GDB 调试程序一般有三种方式: gdb filename gdb attach pid gdb filename corename 这也对应着本节课的核心内容: 直接调试目标程序 附加进程 调 ...

  4. 掌握基于AOP事务管理

    一.手动管理和半自动工厂模式 二.AOP事务管理 1.表达式中,第一个※是返回值所有类型,service包下一个点意思是service包下的类,两个点意思是service包下的类和其子包下的类也包含, ...

  5. JDK 1.7 正式发布,Oracle 官宣免费提供!“新版任你发,我用JDK 8”或成历史?

    Oracle公司JDK 17正式发布,JDK 17属于长期支持(LTS)版本,也就是获得8年的技术支持,自2021年9月至2029年9月截止. JDK 17版本更新了很多比较实用的新特性,关于此版本的 ...

  6. Java技术开发专题系列之【Guava RateLimiter】针对于限流器的入门到精通(针对于源码分析介绍)

    Guava包中限流实现分析 RateLimiter 之前的文章中已经介绍了常用的限流算法,而google在Java领域中使用Guava包中的限流工具进行服务限流. 回顾使用案例 Google开源工具包 ...

  7. Stage 1 项目需求分析报告

    迷你商城后台管理系统-- 需求分析 1. 引言 作为互联网热潮的崛起,消费者们的普遍差异化,实体商城要想在互联网的浪潮中继续发展,就需要制定出针对用户以及消费者的消费习惯以及喜爱品种的消费方案.从而企 ...

  8. PHP设计模式之原型模式

    原型模式其实更形象的来说应该叫克隆模式.它主要的行为是对对象进行克隆,但是又把被克隆的对象称之为最初的原型,于是,这个模式就这样被命名了.说真的,从使用方式来看真的感觉叫克隆模式更贴切一些. Gof类 ...

  9. http升级https遇到的问题

    1. 功能请求失效: 可能是链接为http请求,导致出现问题 2.浏览器网址左边出现黄色感叹号: 这是由于网页中存在http的图片链接,需要根据实际情况修改; 3.将网页内的http请求变为https ...

  10. httpd进程数统计,IP封禁,IP连接数量情况查看

    ps -ef|grep httpd|wc -l 统计httpd进程数,连个请求会启动一个进程,使用于Apache服务器. 查看Apache的并发请求数及其TCP连接状态:netstat -n | aw ...