2025CSP-J 冲刺训练 6
一、基础知识
二、基础应用
1. 无法入睡
1.1 审题
有
n
n
n 间房间排成一排,有些房间亮着灯,有些房间关着灯。
如果一个房间关着灯,但是旁边两个房间都亮着灯,那么这个房间的人就会受到灯光打扰无法入睡。
用
a
i
a_i
ai 表示第
i
i
i 个房间是否开着灯,对于
2
≤
i
≤
n
−
1
2≤i≤n−1
2≤i≤n−1,如果
a
i
=
0
a_i=0
ai=0 且
a
i
−
1
=
a
i
+
1
=
1
a_{i-1}=a_{i+1}=1
ai−1=ai+1=1 ,那么第
i
i
i 个房间的人就受到打扰。
现在给出哪些房间开着灯,问最少关掉多少房间的灯,就可以让所有关着灯的房间的人不受到打扰。
1.2 分析
题目定义:如果第
i
i
i 个房间无法入睡,则第
i
i
i 个房间的元素为
0
0
0,第
i
−
1
i-1
i−1 和
i
+
1
i+1
i+1 的房间都为
1
1
1。
突破点是列举,假如有这样的一个 a[]
:
{
1
,
0
,
1
,
0
,
1
}
\{ 1,0,1,0,1 \}
{1,0,1,0,1}
显然,我们只需要关掉第
3
3
3 个房间的灯即可让无法入睡的第
2
,
4
2,4
2,4 号房间入睡。
所以我们推测出,遇到一个房间无法入睡时,关闭其右侧房间的灯时最优解。
1.3 参考答案
#include<bits/stdc++.h>
using namespace std;
const int MAXN=108;
int n,a[MAXN],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i+2<=n;i++)
if(a[i]==1&&a[i+1]==0&&a[i+2]==1)
ans++,a[i+2]=0;
cout<<ans;
return 0;
}
2. 均富卡
2.1 审题
有一个数列
a
1
∼
a
n
a_1\sim a_n
a1∼an。可以对它进行如下操作:
每次操作,选择数列的一个子序列(也可以是数列本身),将子序列中的数都改成它们的平均数。
例如数列
{
5
,
1
,
2
,
1
}
\{ 5,1,2,1 \}
{5,1,2,1},选择第
1
1
1 个数和第
3
3
3 个数,它们的平均数是
3.5
3.5
3.5,所以操作后数列就会变成
{
3.5
,
1
,
3.5
,
1
}
\{ 3.5,1,3.5,1 \}
{3.5,1,3.5,1}。
给出数列
a
1
∼
a
n
a_1\sim a_n
a1∼an 和一个整数
x
x
x,我们想要通过若干次操作,让尽可能多的数大于等于
x
x
x。问最多可以使多少个数大于等于
x
x
x?(操作的次数没有上限,也可以一次都不操作)
2.2 分析
如果要让 n n n 个数 ≥ x \ge x ≥x,则 a 1 ∼ a n a_1\sim a_n a1∼an 的和应该至少为 x n xn xn。我们可以每次都踢出最小的数,然后判断剩下的总和是否为 x × x\times x×元素个数。
2.3 参考答案
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+8;
int t,n,x,a[MAXN];
int main(){
cin>>t;
while(t--){
cin>>n>>x;
long long sum=0;
for(int i=1;i<=n;i++)
cin>>a[i],sum+=a[i];
sort(a+1,a+n+1);
for(int j=0;j<=n;j++){//踢走的元素下标
sum-=a[j];//每次踢走一个最小的元素
if(sum>=1ll*(n-j)*x){//看是否能满足条件(等价于sum/(n-j)>=x,但除法有精度损失)
cout<<n-j<<endl;
break;
}
}
}
return 0;
}
3. 与怪物战斗
3.1 审题
有
n
n
n 个怪物排队等待玩家来消灭它们。第
i
i
i 个怪物的体力为
h
i
h_i
hi。玩家 A 的攻击力为
a
a
a,玩家 B 的攻击力为
b
b
b。
对于每只怪物,两位玩家按如下顺序交替行动,直到怪物血量小于等于
0
0
0:
(1)玩家 A 攻击怪物,怪物血量减少
a
a
a。如果攻击后怪物血量小于等于
0
0
0,玩家 A 得到
1
1
1 分。
(2)玩家 B 攻击怪物,怪物血量减少
b
b
b。如果攻击后怪物血量小于等于
0
0
0,玩家A不得分。
每个怪都是由 A 先发起攻击。
玩家 A 另外有一种特殊能力,可以迫使B放弃一次攻击。他最多可以使用这个能力
k
k
k 次。
求出玩家 A 最多可以得到多少分。
3.2 分析
只要思考一下就能发现,我们只需要让怪物要砍的个数为:
(
(
h
[
i
]
−
1
)
m
o
d
(
a
+
b
)
)
/
a
((h[i]-1) \mod (a+b))/a
((h[i]−1)mod(a+b))/a
就可以使 A 成功完成任务。
3.3 参考答案
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+8;
int n,a,b,k,h[MAXN];
int main(){
cin>>n>>a>>b>>k;
for(int i=1;i<=n;i++)cin>>h[i];
map<int,int>mp;
for(int i=1;i<=n;i++)
mp[((h[i]-1)%(a+b))/a]++;
int ans=0;
for(auto[r,cnt]:mp){
if(r*cnt<=k)
ans+=cnt,k-=r*cnt;
else{
ans+=k/r;
break;
}
}
cout<<ans;
return 0;
}
三、拓展应用
1. 国王游戏(弱)
1.1 审题
恰逢
H
H
H 国国庆,国王邀请
n
n
n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这
n
n
n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
1.2 分析
1.3 参考答案
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+8;
int n,a,b;
struct Minister{
int a,b;
bool operator<(const Minister&rhs)const{
return a*b<rhs.a*rhs.b;
}
}mins[MAXN];
int main(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++)
cin>>mins[i].a>>mins[i].b;
sort(mins+1,mins+n+1);
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,a/mins[i].b);
a*=mins[i].a;
}
cout<<ans;
return 0;
}