CF958F2 Lightsabers (medium)题解

题解

1.题意

自己看吧,懒得总结了

2.思路

考虑二分

首先,我们可以先选出我们要的区间,再去进行删数

删数十分好做,第 $i$ 个颜色需要删 $当前第i个数出现次数-k_i$ 次

接下来想一想如何选出最优的区间

我们肯定是希望在每个数出现次数不小于 $k_i$ 的前提下,让区间尽可能的小

那我们可以二分 $n-区间长度$ (主要是在check时要做的是删数后判断是否满足条件)

在每一次check里,我们需要枚举缩区间的时候删的是哪些数

这我们可以动态更新

首先假设当前二分的$mid$是 $x$

所以先假设缩区间删除的是前 $x$ 个数

这我们可以先统计

接下来,把区间变为删前 $x-1$ 个数和最后一个数,可以O(1)更新是否满足条件

然后一直这样往左移动区间,就能统计出是否能够合法了

整体复杂度O(n log n)

3.Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<bits/stdc++.h>

using namespace std;
int n,m,k[200010],a[200010],cnt[200010],vis[200010],temp[200010],anscnt[200010];
int check(int x){
int flag=0;
for(int i=1;i<=n;i++)temp[a[i]]=cnt[a[i]];
for(int i=1;i<=x;i++){
cnt[a[i]]--;
if(cnt[a[i]]==k[a[i]]-1)flag++;
}
//cout<<flag<<";\n";
if(flag==0)return 1;
for(int i=1;i<=x;i++){
cnt[a[x-i+1]]++;
if(cnt[a[x-i+1]]==k[a[x-i+1]])flag--;
cnt[a[n-i+1]]--;
if(cnt[a[n-i+1]]==k[a[n-i+1]]-1)flag++;
//cout<<flag<<";\n";
if(flag==0)return 1;
}
return 0;
}
main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],cnt[a[i]]++,anscnt[a[i]]++;
for(int i=1;i<=m;i++)cin>>k[i];
for(int i=1;i<=m;i++){

if(k[i]>cnt[i]){
cout<<-1;
return 0;
}
}
int l=1,r=n;
while(l<=r){
int mid=(l+r)>>1;
//cout<<mid<<endl;
if(check(mid)){
l=mid+1;
for(int i=1;i<=n;i++)anscnt[a[i]]=cnt[a[i]];
for(int i=1;i<=n;i++)cnt[a[i]]=temp[a[i]];
}
else{
r=mid-1;
for(int i=1;i<=n;i++)cnt[a[i]]=temp[a[i]];
}
}
int ans=0;

for(int i=1;i<=n;i++){

if(anscnt[a[i]]!=-1){
ans+=anscnt[a[i]]-k[a[i]];
anscnt[a[i]]=-1;
}
}
cout<<ans;
return 0;
}

CF958F2 Lightsabers (medium)题解
https://zxtweb.fun/posts/cnb-19656802/
作者
站长
发布于
2026年3月1日
许可协议