2025牛客寒假训练营6 J题题解
题目链接:https://ac.nowcoder.com/acm/contest/95338/J
解题思路:分为以下四种情况:
1.如果
y
≥
n
y\geq n
y≥n,那么显然每回合都要磨刀,从某个回合开始连续杀怪,直到游戏结束。设
t
t
t为从第一个回合开始连续不杀怪的回合,设
D
(
t
)
D(t)
D(t)为在前述条件下造成的总伤害值,可以得出
D
(
0
)
=
n
(
x
+
1
)
D(0)=n(x+1)
D(0)=n(x+1)。然后由特殊推一般,可得
D
(
t
)
=
(
n
−
t
)
(
x
+
1
−
t
)
D(t)=(n-t)(x+1-t)
D(t)=(n−t)(x+1−t)。令
∂
D
∂
t
=
0
\frac{\partial D}{\partial t}=0
∂t∂D=0可得,
t
=
n
−
(
x
+
1
)
2
=
t
0
t=\frac{n-(x+1)}{2}=t_0
t=2n−(x+1)=t0。此时再分为以下两种情况:
1)如果
n
≤
x
+
1
n\leq x+1
n≤x+1,那么显然当
t
=
0
t=0
t=0时
D
(
t
)
D(t)
D(t)取得最大值
D
(
0
)
D(0)
D(0)。
2)否则,当
t
=
t
0
t=t_0
t=t0时取得最大值,最大值为
(
n
+
x
+
1
)
2
4
\frac{(n+x+1)^2}{4}
4(n+x+1)2。但这里要注意一点,如果
n
%
2
≠
(
x
+
1
)
%
2
n\%2\neq(x+1)\%2
n%2=(x+1)%2,那么最大值为
D
(
t
0
)
−
1
4
D(t_0)-\frac{1}{4}
D(t0)−41。
综上所述,
D
max
=
{
n
(
x
+
1
)
n
≤
x
+
1
⌊
(
n
+
x
+
1
)
2
4
⌋
n
>
x
+
1
D_{\max}=\begin{cases} n(x+1)&n\leq x+1 \\ \lfloor\frac{(n+x+1)^2}{4}\rfloor & n>x+1\end{cases}
Dmax={n(x+1)⌊4(n+x+1)2⌋n≤x+1n>x+1。
2.如果
x
+
2
y
−
1
≤
n
x+2y-1\leq n
x+2y−1≤n,那么最优解就是先把刀磨到最亮(攻击力为
x
+
y
x+y
x+y),然后从用完最后一个磨刀石的回合开始杀怪,直到把刀用坏。此时造成的总伤害值就是
(
x
+
y
)
(
x
+
y
+
1
)
2
\frac{(x+y)(x+y+1)}{2}
2(x+y)(x+y+1)。
3.如果
x
+
2
y
−
1
>
n
x+2y-1>n
x+2y−1>n,这时就要看从哪个回合开始杀怪可以造成最大伤害值。容易证明,最优解肯定在前y次的范围内。设
t
t
t为从第一个回合开始连续不杀怪的回合,设
D
(
t
)
D(t)
D(t)为在前述条件下造成的总伤害值。显然,用完最后一个磨刀石的那一个回合结束后时,刀的攻击力为
x
+
t
x+t
x+t,如果
x
+
t
≤
n
−
y
x+t\leq n-y
x+t≤n−y,那么游戏还没结束,刀就被用坏了,此时
D
(
t
)
=
(
x
+
1
+
t
)
(
y
−
t
)
+
(
x
+
t
)
(
x
+
t
+
1
)
2
D(t)=(x+1+t)(y-t)+\frac{(x+t)(x+t+1)}{2}
D(t)=(x+1+t)(y−t)+2(x+t)(x+t+1);否则,这把刀足够用剩下的
(
n
−
y
)
(n-y)
(n−y)个回合,此时
D
(
t
)
=
(
x
+
1
+
t
)
(
y
−
t
)
+
(
n
−
y
)
(
(
x
+
t
)
+
(
x
+
t
+
1
−
(
n
−
y
)
)
2
D(t)=(x+1+t)(y-t)+\frac{(n-y)((x+t)+(x+t+1-(n-y))}{2}
D(t)=(x+1+t)(y−t)+2(n−y)((x+t)+(x+t+1−(n−y)),此时答案为
min
t
∈
[
0
,
n
]
D
(
t
)
\min_{t\in[0,n]}D(t)
mint∈[0,n]D(t)。这种情况似乎没办法用一个多元初等函数来表示,只能跑暴力寻找解。好在
O
(
T
y
)
\mathcal O(Ty)
O(Ty)的时间复杂度可以通过本题。
#include<iostream>
#include<iomanip>
#include<cstring>
#include<numeric>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<climits>
#include<array>
#include<queue>
#include<bitset>
#define int long long
#define cd(n,d) std::cout<<std::fixed<<std::setprecision((n))<<(d)
#define ms(a,b) std::memset((a),(b),sizeof(a))
#define mc(a,b) std::memcpy((a),(b),sizeof(b))
#define all(v) (v).begin(),(v).end()
#define _all(v,n) (v),(v)+(n)
#define sum(v,x) std::accumulate((v).begin(),(v).end(),(x))
#define _sum(v,n,x) std::accumulate((v),(v)+(n),(x))
#define fill(v,x) std::fill((v).begin(),(v).end(),(x))
#define iota(v,x) std::iota((v).begin(),(v).end(),(x))
#define _fill(v,n,x) std::fill((v),(v)+(n),(x))
#define _iota(v,n,x) std::iota((v),(v)+(n),(x))
#define cln std::cout<<"\n"
#define eb emplace_back
#define pb pop_back
#define ef emplace_front
#define pf pop_front
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define FOR0(i,x,y) for(int i=(x);i<(y);i++)
#define _FOR(i,x,y) for(int i=(x);i>=(y);i--)
#define _FOR0(i,x,y) for(int i=(x);i>(y);i--)
#define F first
#define S second
using PII=std::pair<int,int>;
void solve(){
int n,x,y;
std::cin>>n>>x>>y;
if(y>=n){
if(n<=x+1){
std::cout<<n*(x+1)<<"\n";
}else{
std::cout<<(n+1+x)*(n+1+x)/4<<"\n";
}
}else{
if(x+2*y-1<=n){
std::cout<<(x+y)*(x+y+1)/2<<"\n";
}else{
int ans=0;
FOR(t,0,y){
int damage;
if(x+y+t>n){
damage=(x+1+t)*(y-t)+(n-y)*((x+1+t-1)+(x+1+t-(n-y)))/2;
}else{
damage=(x+1+t)*(y-t)+(x+t)*(x+1+t)/2;
}
ans=std::max(ans,damage);
}
std::cout<<ans<<"\n";
}
}
}
signed main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T=1;
std::cin>>T;
while(T--){
solve();
}
return 0;
}