[洛谷P4774] [NOI2018]屠龙勇士
洛谷题目链接:[NOI2018]屠龙勇士
因为markdown复制过来有点炸格式,所以看题目请戳上面.
题解: 因为杀死一条龙的条件是在攻击\(x\)次,龙恢复\(y\)次血量\((y\in N^{*})\)后龙的血量恰好为\(0\).那么根据题意我们可以列出方程:
\]
这个形式是不是很像中国剩余定理的形式:\(x\equiv b_i(mod \ a_i)\).
事实上我们可以直接将这个方程看做一个同余方程,即$$atk_ix+p_iy = hp_i$$
那么这个式子就代表着攻击了\(x\)次,恢复了\(-y\)次血量,因为解出来的\(x\)和\(y\)一定是一正一负的.这样求解的话,我们就需要考虑\(y\)的定义域了.但是事实上不用每次都用最小合法解,只需要每次找到一个解,最后求出整个方程组的解的时候将解构造成合法的形式.因为每次攻击龙都会解出来一个解\(x_i\),最后求出来的解只要保证\(ans>=max\{x_i\}\)就一定是合法的了.
这样的话,合并上面这个式子就只剩下中国剩余定理的部分了.设\(lcm=lcm\{p_i\},i\in[1,k-1]\),\(x_0\)为前\(k-1\)个同余方程的解,那么\(x_0+t*lcm\)也一定是前\(k-1\)个方程的解,为了满足第\(k\)个式子,那么我们需要找到一个\(t\)使得$$(x_0+tlcm)atk_i\equiv hp_i(mod \ p_i)$$
\]
设\(a=lcm*atk_i,b=p_i,c=hp_i-atk_i*x_0,x=t\),则有\(a*x+b*y=c\),也就是同余方程的标准形式.
我们应该如何判断无解呢?对于这样的不定方程,有解的条件为\(gcd(a,b)|c\),在做\(exgcd\)的时候判断一下就可以了.
那么每求出\(t\)的一个解,就可以得到前\(k\)个同余方程的解\(x_0+t*lcm\),做完之后再更新一下\(lcm=lcm(lcm, p_i)\)就可以了.
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
const int inf = 0x3f3f3f3f;
typedef int _int;
#define int long long
int T, n, m, hp[N], p[N], rew[N], cnt = 0, root, r1, r2, r3, ans = 0, mx;
struct treap{
int ch[2], val, rd, size;
treap(){ ch[0] = ch[1] = val = rd = size = 0; }
}t[N*2];
int newnode(int val){
t[++cnt].val = val, t[cnt].rd = rand(), t[cnt].size = 1;
return cnt;
}
void up(int x){ t[x].size = t[t[x].ch[0]].size+t[t[x].ch[1]].size+1; }
void split(int x, int val, int &a, int &b){
if(!x){ a = b = 0; return; }
if(t[x].val <= val) a = x, split(t[x].ch[1], val, t[x].ch[1], b);
else b = x, split(t[x].ch[0], val, a, t[x].ch[0]); up(x);
}
int merge(int x, int y){
if(!x || !y) return x+y;
if(t[x].rd < t[y].rd){
t[x].ch[1] = merge(t[x].ch[1], y);
up(x); return x;
} else {
t[y].ch[0] = merge(x, t[y].ch[0]);
up(y); return y;
}
}
void insert(int val){
split(root, val, r1, r2);
root = merge(r1, merge(newnode(val), r2));
}
void delet(int val){
split(root, val-1, r1, r2), split(r2, val, r2, r3);
r2 = merge(t[r2].ch[0], t[r2].ch[1]);
root = merge(r1, merge(r2, r3));
}
int exgcd(int a, int b, int &x, int &y){
if(!b){ x = 1, y = 0; return a; }
int gcd = exgcd(b, a%b, x, y), tmp;
tmp = y, y = x-a/b*y, x = tmp;
return gcd;
}
int getv(int val){
int res = 0, node; split(root, val, r1, r2);
if(!t[r1].size){
node = r2;
while(t[node].ch[0]) node = t[node].ch[0];
} else {
node = r1;
while(t[node].ch[1]) node = t[node].ch[1];
}
root = merge(r1, r2); return t[node].val;
}
int mul(int a, int b, int mod){
int res = 0;
for(; b; b >>= 1, (a += a) %= mod)
if(b & 1) (res += a) %= mod;
return res;
}
void work(){
int x, y, v, M = 1, C, gcd; cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> hp[i];
for(int i = 1; i <= n; i++) cin >> p[i];
for(int i = 1; i <= n; i++) cin >> rew[i];
for(int i = 1; i <= m; i++) cin >> x, insert(x);
for(int i = 1; i <= n; i++){
v = getv(hp[i]), mx = max(mx, hp[i]/v+(hp[i]%v != 0));
C = (hp[i]-(mul(ans, v, p[i]))%p[i]+p[i])%p[i];
gcd = exgcd(M*v, p[i], x, y);
if(C % gcd != 0){ cout << -1 << endl; return; }
x = mul(x, C/gcd, p[i]), ans += x*M;
M *= p[i]/gcd, ans = (ans%M+M)%M;
delet(v), insert(rew[i]);
}
cerr << "mx=" << mx << endl;
if(ans < mx) ans += M*((mx-ans-1)/M+1);
cout << ans << endl;
}
void clear(){
for(int i = 1; i <= cnt; i++)
t[i].ch[0] = t[i].ch[1] = t[i].rd = t[i].size = t[i].val = 0;
ans = cnt = root = 0, mx = -inf;
}
_int main(){
freopen("dragon1.in", "r", stdin);
ios::sync_with_stdio(false);
srand(time(NULL));
cin >> T;
while(T--) work(), clear();
return 0;
}
[洛谷P4774] [NOI2018]屠龙勇士的更多相关文章
- 洛谷 P4774 [NOI2018] 屠龙勇士
链接:P4774 前言: 交了18遍最后发现是多组数据没清空/ll 题意: 其实就是个扩中. 分析过程: 首先发现根据题目描述的选择剑的方式,每条龙对应的剑都是固定的,有查询前驱,后继(在该数不存在前 ...
- (伪)再扩展中国剩余定理(洛谷P4774 [NOI2018]屠龙勇士)(中国剩余定理,扩展欧几里德,multiset)
前言 我们熟知的中国剩余定理,在使用条件上其实是很苛刻的,要求模线性方程组\(x\equiv c(\mod m)\)的模数两两互质. 于是就有了扩展中国剩余定理,其实现方法大概是通过扩展欧几里德把两个 ...
- 洛谷P4774 [NOI2018]屠龙勇士 [扩欧,中国剩余定理]
传送门 思路 首先可以发现打每条龙的攻击值显然是可以提前算出来的,拿multiset模拟一下即可. 一般情况 可以搞出这么一些式子: \[ atk_i\times x=a_i(\text{mod}\ ...
- P4774 [NOI2018]屠龙勇士
P4774 [NOI2018]屠龙勇士 先平衡树跑出打每条龙的atk t[] 然后每条龙有\(xt \equiv a[i](\text{mod }p[i])\) 就是\(xt+kp[i]=a[i]\) ...
- luogu P4774 [NOI2018]屠龙勇士
传送门 这题真的是送温暖啊qwq,而且最重要的是yyb巨佬在Day2前几天正好学了crt,还写了博客 然而我都没仔细看,结果我就同步赛打铁了QAQ 我们可以先根据题意,使用set维护,求出每次的攻击力 ...
- 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 每次用 ...
- uoj396 [NOI2018]屠龙勇士
[NOI2018]屠龙勇士 描述 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照编号 1∼n 顺序杀掉 n 条巨龙,每条巨龙拥有一个初始的生命值 ai .同时每条巨龙拥有恢复能 ...
- 洛谷P4774 BZOJ5418 LOJ2721 [NOI2018]屠龙勇士(扩展中国剩余定理)
题目链接: 洛谷 BZOJ LOJ 题目大意:这么长的题面,就饶了我吧emmm 这题第一眼看上去没法列出同余方程组.为什么?好像不知道用哪把剑杀哪条龙…… 仔细一看,要按顺序杀龙,所以获得的剑出现的顺 ...
随机推荐
- 《Linux/UNIX系统编程手册》读书笔记
2018-1-30 一.UNIX.C语言以及Linux的历史回顾 1. UNIX简史.C语言的诞生 1969年,贝尔实验室的Ken Thompson首次实现了UNIX系统. 1973年,C语言步入成熟 ...
- Java中终止正在运行线程
问题:java 中如何让一个正在运行的线程终止掉? Demo_1: class TT implements Runnable { private boolean flag = true; @Overr ...
- TCP系列08—连接管理—7、TCP 常见选项(option)
一.TCP选项概述 在前面介绍TCP头的时候,我们说过tcp基本头下面可以带有tcp选项,其中有些选项只能在连接过程中随着SYN包发送,有些可以延后.下表汇总了一些tcp选项 其中我标记为红色的部分是 ...
- Personal summary 个人总结
一.请回望开学时的第一次作业,你对于软件工程课程的想象 对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强计算机专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方面达 ...
- Window命令行工具操作文件
1,cd 命令用来切换目录 2,mkdir用来创建文件夹 3,rmdir用来删除空文件夹 4,创建指定类型的文件 type nul>"文件名和后缀" 5,打开指定文件用sta ...
- oracle 9i 图文安装教程 oracle 9i 安装
我的安装文件是ISO镜像文件,使用Virtual DAEMON Manager v 4.10打开: ora9i-1.iso ora9i-2.iso ora9i-3.iso 首先必须把上面三个镜像文件都 ...
- Python爬虫requests判断请求超时并重新发送请求
下面是简单的一个重复请求过程,更高级更简单的请移步本博客: https://www.cnblogs.com/fanjp666888/p/9796943.html 在爬虫的执行当中,总会遇到请求连接 ...
- delphi 取得数据集某字段值的六种方法
//取name字段的示例 edit1.Text:=ADOquery1.Fields[2].AsString; //取得数据表的第二个字段的值 edit2.Text:=ADOquery1.Fie ...
- DELPHI的MEMO组件
位于Standard选项卡上,它是对EDIT控件的扩展,可以对多行文本进行显示.输入 和编辑. Lines属性: 该属性实际上为TStrings类型的对象,用来存放Memo对象的文本 TStrings ...
- Python程序性能分析模块----------cProfile
cProfile分析器可以用来计算程序整个运行时间,还可以单独计算每个函数运行时间,并且告诉你这个函数被调用多少次 def foo(): pass import cProfile cProfile.r ...