Link-Cut-Tree
LOJ - https://loj.ac/problem/2721
Luogu - https://www.luogu.org/problemnew/show/P4774
BZOJ - https://www.lydsy.com/JudgeOnline/problem.php?id=5418
Deskappation
有
n
n
n 条巨da的黑炎龙(Darkflame
’s 玛斯塔
\tiny\colorbox{#000000}{\color{#000000}{'s 玛斯塔}}
’s 玛斯塔) 每条黑炎龙都有
a
i
a_i
ai 的生命值
+ 一条黑炎龙当且仅当HP为
0
0
0 的时候会低头
- 每条黑炎龙如果HP为负数就可以自动恢♂复HP直到非负。
- 每次恢复
p
p
p 点HP。可以认为它恢复得非常快,只要负了、一瞬间就会回血到非负。
+ 玩家有
m
m
m 把大保健,杀死每只龙会少一条大保健,然后龙会喷装屠龙宝刀点击就送一刀999
小DD颓这个游戏的时候觉得推起来索然无味,但是最快通关介款游戏你就可以AK ION8102
然后小DD化身机器人认识它(指苣龙)的美
+ 小DD会每次单推一条龙;
- 我们钦定了小DD必须按照
1
∼
n
1\sim n
1∼n 的顺序单推
+ 每一轮单推,小DD一出生(指开始屠一条龙),他会选攻击力不高于苣龙初始HP的剑里面攻击力最大的一把;
- 如果没有,就选攻击力最低的
+ 作为冷酷的复读机器人,单推巨龙的时候小DD会用他选好的大保健连续攻击
x
x
x 次
- 当然显然肯定一定会产生
x
⋅
A
T
K
x\cdot ATK
x⋅ATK 的DMG
求复读机最少复读几次公鸡打鸣
咕咕咕
\tiny\colorbox{#000000}{\color{#000000}{咕咕咕}}
咕咕咕之后能够通关
如果无法通关,输出
−
1
-1
−1 ,表示复读机会一直复读下去(快乐)
如果无法通关,输出
−
1
-1
−1 ,表示复读机会一直复读下去(快乐)
如果无法通关,输出
−
1
-1
−1 ,表示复读机会一直复读下去(快乐)
如果无法通关,输出
−
1
-1
−1 ,表示复读机会一直复读下去(快乐)
(快乐)
(笔芯)
测试点编号 | 攻击力 | 其他限制 | ||||
---|---|---|---|---|---|---|
1 | 无 | |||||
2 | ||||||
3 | ||||||
4 | ||||||
5 | 特性 1、特性 2 | |||||
6 | ||||||
7 | ||||||
8 | 特性 1 | |||||
9 | ||||||
10 | ||||||
11 | ||||||
12 | ||||||
13 | ||||||
14 | 无特殊限制 | |||||
15 | ||||||
16 | 所有 是质数 | 特性 1 | ||||
17 | ||||||
18 | 无特殊限制 | |||||
19 | ||||||
20 |
AnalysⅠs
注意到所有的数据必定满足 BUG1 或者
p
i
=
1
p_i=1
pi=1
Feature1: ∀ i , a i ≤ p i \forall i,a_i\le p_i ∀i,ai≤pi
首先显然可以列一个方程组
{
a
i
−
x
j
⋅
a
t
k
j
+
k
⋅
p
i
=
0
\begin{cases} \begin{array}{rcl}a_i-x_j\cdot atk_j+k\cdot p_i=0 \end{array} \end{cases}
{ai−xj⋅atkj+k⋅pi=0
哦(冷漠)
满足
∀
i
,
a
i
≤
p
i
\forall i,a_i\le p_i
∀i,ai≤pi 或者
p
i
=
1
p_i=1
pi=1
那么
a
i
≡
x
⋅
a
t
k
j
(
m
o
d
p
i
)
a_i\equiv x\cdot atk_j\pmod{p_i}
ai≡x⋅atkj(modpi) 或者
x
≥
⌈
a
i
a
t
k
j
⌉
x\ge\Large\lceil\frac{a_i}{atk_j}\rceil
x≥⌈atkjai⌉
后面那个处理一下,
对前面那个联立线性同余方程组ExCRT即可。
(实际上可以分类处理,……不难)
a i ≡ x ⋅ a t k j ( m o d p i ) a_i\equiv x\cdot atk_j\pmod{p_i} ai≡x⋅atkj(modpi)
x ≡ a i ⋅ i n v ( a t k j ) ( m o d p i ) x\equiv a_i\cdot inv(atk_j)\pmod{p_i} x≡ai⋅inv(atkj)(modpi)
需要注意的是 i n v ( a t k j ) inv(atk_j) inv(atkj) 不一定存在。(看到逆元就应该注意这个)
只需把 a i , a t k j , p i a_i,atk_j,p_i ai,atkj,pi 同除它们的GCD即可……还是不行就无解了
有一个问题是
a
t
k
j
atk_j
atkj 怎么搞来啊……
……
……这个显然可以预处理嘛………………
没错这道题的确就完了,不要怀疑
(我打代码好慢啊
像cxk
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<queue>
#include<set>
#include<ctime>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 114514;
int T, n, m;
long long a[MAXN];
long long p[MAXN];
long long Rew[MAXN];
long long Atk[MAXN];
long long atk[MAXN];
bool csk;
inline long long Mul(const long long& a, const long long& b, const long long& p)
{
static long long t;
t = (long double) a * b / p;
return a * b - t * p;
}
inline long long Adjust(const long long& x, const long long& p)
{
static long long t;
t = x % p + p;
return (t >= p) ? (t - p) : t;
}
inline long long gcd(const long long& a, const long long& b)
{
return !b?a:gcd(b, a%b);
}
inline void exgcd(long long a, long long b, long long& d,long long& x, long long& y)
{
!b?(d=a,x=1,y=0):(exgcd(b,a%b,d,y,x),y-=x*(a/b));
}
inline long long inv(const long long& X, const long long& P)
{
static long long d, x, y;
exgcd(X, P, d, x, y);
return Adjust(x, P);
}
inline void Input()
{
csk = 0;
scanf("%d%d", &n, &m);
for (register int i = 1; i <= n; ++i)
{
scanf("%lld", &a[i]);
}
for (register int i = 1; i <= n; ++i)
{
scanf("%lld", &p[i]);
if(p[i]!=1)csk=1;
}
for (register int i = 1; i <= n; ++i)
{
scanf("%lld", &Rew[i]);
}
for (register int i = 1; i <= m; ++i)
{
scanf("%lld", &Atk[i]);
}
}
multiset<long long>List;
inline bool Decide()
{
List.clear();
for (register int i = 1; i <= m; ++i) List.insert(Atk[i]);
register multiset<long long>::iterator iter;
for (register int i = 1; i <= n; ++i)
{
if(List.empty()) return 1;
iter = List.upper_bound(a[i]);
if(iter!=List.begin()) --iter;
atk[i] = *iter;
List.erase(iter);
List.insert(Rew[i]);
}
return 0;
}
long long Ans, Lim;
bool liv[MAXN];
bool gaq;
inline void Init()
{
gaq = 0;
Lim = 0;
memset(liv, 0, sizeof(liv));
Ans = 0;
}
inline bool Structure()
{
static long long tem, temtem;
register bool fafa = 0;
Init();
for (register int i = 1; i <= n; ++i)
{
if (!csk)
{
Lim = max(Lim, (long long)ceil(1.0 * a[i] / atk[i]));
}
else
{
fafa = 1;
tem = gcd(atk[i], p[i]);
temtem = gcd(tem, a[i]);
a[i] /= temtem; atk[i] /= temtem; p[i] /= temtem;
if (temtem<tem) return 1;
a[i] = Mul(a[i], inv(atk[i], p[i]), p[i]);
}
}
if(!csk)
{
gaq = 1;
printf("%lld\n", Lim);
return 1;
}
return 0;
}
inline bool ExCRT()
{
static long long A, M, k, K, G, T;
A = a[1], M = p[1];
for (register int i = 2; i <= n; ++i)
{
exgcd(M, p[i], G, K, k);
T=A-a[i];
if (T%G) return 1;
K = Mul(K, (T/G), p[i]);
T = M;
M = M*(p[i]/G);
A = Adjust(A - Mul(K, T, M), M);
}
printf("%lld\n", A);
return 0;
}
int main()
{
freopen("dragon.in","r",stdin);
freopen("dragon.out","w",stdout);
scanf("%d", &T);
while (T--)
{
Input();
if (Decide())
{
printf("-1\n");
continue;
}
if (Structure())
{
if(gaq) continue;
printf("-1\n");
continue;
}
if (ExCRT())
{
printf("-1\n");
continue;
}
}
return 0;
}